Java笔记--多态

        “我曾经被问到‘求教,Baddage先生,如果你向机器中输入错误的数字,可以得到正确的答案吗?’ 我无法恰当地理解产生这种问题的概念上的混淆。”

                                                                                          --Charles Babbage(1791-1871)

1、多态的概述 

        多态方法的调用允许一种类型表现处与其他相似类型之间的区别,只要他们是从同一个基类中导出而来的。这种区别是根据方法行为的不同而表现出来的,虽然这些方法都可以通过同一个基类来调用。

简单的说,某一个事物在不同状态下的多种状态

2、实现多态的三大前提

  • 必须要有继承关系
  • 要有方法的重写(思考可否不重写?)

        不是必须要重写的,重写可以体现子类的专属特征。

  • 要有父类的引用指向子类对象

使用多态第三个前提的注意事项:

        1.必须是继承关系的类,才可以写成父类的引用指向子类对象

        2.左边的父类,可以不必是子类对象的直接父类,也可以是父类的父类

代码体现

package day09;
class Demo1{

}

class Power{

}

class Water extends Power{
    public void getPower(){
        System.out.println("提供能量");
    }
}

class GutaiWater extends Water{
    @Override
    public void getPower(){
        System.out.println("可以嚼着吃");
    }
}



public class DuoTaiDemo1 {
    public static void main(String[] args) {
        //Demo1 w1 = new GutaiWater();   
        // 错误的,Demo1类与GutaiWater类没有继承关系
        Water w2 = new GutaiWater();//从右往左读,固态的水是水
        Power p1 = new GutaiWater();
    }
}

3、访问成员的特点

多态下,访问成员的特点:

1、成员变量

编译看左,允许看左。

2、成员方法

编译看左,运行看右。

思考:如何在多态的状态下,使用子类中特有的方法呢?

3、静态的成员方法

编译看左,运行看左。

package day09;

class Fu1{
    int a1 = 10;

    public void fun1(){
        System.out.println("这是父类中的非静态方法fun1");
    }
    public static void fun2(){
        System.out.println("这是父类中的静态方法fun2");
    }
}
 class Zi1 extends Fu1{
    int a = 11;
    @Override
     public void fun1(){
        System.out.println("子类中重写的非静态方法fun1");
    }

    public void show1(){
        System.out.println("天天向上,好好学习!");
    }

    public static void fun2(){
        System.out.println("这是子类中的静态方法fun2");
    }
 }

public class DuoTaiDemo2 {
    public static void main(String[] args) {
        //使用多态的方式创建一个子类对象
        Fu1 f1 = new Zi1();
        System.out.println(f1.a1); // 编译的时候,看左边父类中是否有该变量存在,若存在,编译不报错,运行的结果也是取父类中该变量的值。
        f1.fun1();// 编译的时候,看左边父类中是否有该方法存在,若存在,编译不报错,运行的结果也是取子类的中该方法的实现。
//        f1.show1();
//        f1.fun2(); // 静态的成员方法是跟随类走的,什么类型的变量调用静态方法,就是该类中的静态方法
        Fu1.fun2();
//        Zi1 zi1 = new Zi1();
//        System.out.println(zi1.a1);
    }
}

4、多态的好处

1.提高了程序的维护性(继承)

2.提高了程序的扩展性(多态)

可以从通用的基类继承出新的数据类型,从而新添加一些功能,而那些操纵基类接口的方法不需要任何改动就可以应用于新类。

package day09;

import java.nio.channels.Pipe;

/*
    多态的好处
        1、提高了程序的维护性(由继承保证)
        2、提高了程序的扩展性(由多态保证)

 */
class Animal{
    String name;
    int age;

    public Animal() {
    }

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat(){
        System.out.println("吃");
    }

    public void sleep(){
        System.out.println("睡");
    }
}

class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("🐕吃🥩");
    }

    @Override
    public void sleep() {
        System.out.println("🐕侧着睡");
    }
}

class Pig extends Animal{
    @Override
    public void eat() {
        System.out.println("🐖吃杂食");
    }

    @Override
    public void sleep() {
        System.out.println("🐖趴着睡");
    }
}

class Snake extends Animal{
    @Override
    public void eat() {
        System.out.println("🐍吃🐀");
    }

    @Override
    public void sleep() {
        System.out.println("🐍盘着睡");
    }
}

class Tiger extends Animal{
    @Override
    public void eat() {
        System.out.println("🐅吃🥩");
    }

    @Override
    public void sleep() {
        System.out.println("🐅趴着睡");
    }
}

//写一个工具类,对每一个动物调用吃和睡的功能
class AnimalTool{
    private AnimalTool(){}

//    public static void useDog(Dog dog){
//        dog.eat();
//        dog.sleep();
//    }
//
//    public static void usePig(Pig pig){
//        pig.eat();
//        pig.sleep();
//    }
//
//    public static void useSnake(Snake snake){
//        snake.eat();
//        snake.sleep();
//    }

    public static void useAnimal(Animal animal){ //Animal animal = new Tiger();
        animal.eat();
        animal.sleep();
    }
}




public class DuoTaiDemo5 {
    public static void main(String[] args) {
        //我想一只🐕
        Dog d1 = new Dog();
//        d1.eat();
//        d1.sleep();
        //使用工具类的方式调用动物的吃和睡的功能
//        AnimalTool.useDog(d1);
        AnimalTool.useAnimal(d1);

        //我想一只🐖
        Pig p2 = new Pig();
//        p2.eat();
//        p2.sleep();
//        AnimalTool.usePig(p2);
        AnimalTool.useAnimal(p2);

        //我想养🐍
        //按照上面的写法,应该先写一个🐍的类,然后在类中重写eat和sleep方法
        //在工具类中添加一个调用🐍的吃和睡的方法
        Snake s1 = new Snake();
//        AnimalTool.useSnake(s1);
        AnimalTool.useAnimal(s1);

        //随着我们要养动物的种类越来越多,每一种动物都需要经过上面两个步骤
        //创建该动物的类我们能理解,这是必须要有的
        //但是第二步在工具类进行添加修改其实是有问题。
        //今后的开发中,工具类是不允许频繁修改的。
        //但是我们不添加方法的话,就没法使用工具类调用具体动物的功能
        //于是,我们就在想,怎么可以只在工具类中写一个方法,可以调用所有动物的功能呢?
        //可以使用多态来实现。
        //我现在养一只🐅
        Tiger t1 = new Tiger();
        AnimalTool.useAnimal(t1); // new Tiger()


    }
}

5、多态的弊端

弊端:在多态的形式下,无法使用子类中特有的成员方法

解决方案:向下转型(曹操和曹植的故事)

曹操和曹植的故事,曹操是曹植的父亲,曹植是曹操的儿子
class 曹操{
    public void skill(){
        带兵打仗
    }
}

class 曹植 extends 曹操{
    @Override
    public void skill(){
         下棋
    }

    public void zuoShi(){
        作诗
    }
}

某一天,曹操带兵打仗出城了,城里只有曹植,这时候刘备待人过来攻打城池,但是小兵只听曹操的指令。
为了守护城池,曹植想到一个办法,装爹,粘上胡子,穿上爹的衣服,调用跟爹一样的skill方法。
//向上转型
曹操 c1 = new 曹植();
c1.skill();
// c1.zuoShi(); 不能调用
曹操打仗回来了,曹植看到父亲回来后,不用继续装爹,做回自己,脱掉爹的衣服,撕掉假胡子
//向下转型
曹植 c2 = (曹植) c1;
c2.skill();
c2.zuoShi();

 代码展示:


package day09;
class Fu2{
    public void fun1(){
        System.out.println("Hello World");
    }
}

class Zi2 extends Fu2{
    @Override
    public void fun1(){
        System.out.println("Hello Java");
    }

    public void show1(){
        System.out.println("编程有意思");
    }
}

public class DuoTaiDemo3 {
    public static void main(String[] args) {
        Fu2 f1 = new Zi2();
        f1.fun1();
//            f1.show();//根据多态访问成员的特点,编译看左,父类中没有show1方法,编译报错。
        //向下转型
        Zi2 z1 = new Zi2();
        z1.show1();
    }
}

但是向下转型同样也会遇到问题,在Java中所有的转型都会得到检查,以便保证它是我们想得到的类型。如果不是,就会返回一个ClassCastException(类转型异常)。这种在运行期间对类型进行检查的行为被称为“运行时类型识别”(RTTI)。

6、抽象类

1、抽象方法

Java中提供一个叫做抽象方法的机制,这种方法是不完整的;仅有

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值