多态知识点总结

目录

引出多态思想

多态

1.多态概述

2.多态的前提

3.多态访问成员的特点

4.多态的题目——”套娃“

5.多态的猫狗案例

6.多态的好处

7.多态的弊端

8.多态中的转型问题

9.向下转型的例子及内存解释

10.多态的练习


引出多态思想

       举例:

              水:固态,液态,气态

                     固态的水是水,液态的水是水,气态的水也是水

             水果:西瓜,菠萝,葡萄

                        西瓜是水果,菠萝是水果,葡萄是水果

             动物:狗,猫,兔子

                        狗是动物,猫是动物,兔子是动物

可以说狗是动物,西瓜是水果,但是反过来说却是错误的,不能说水果是西瓜,动物是狗

综上所述,这就是多态思想

多态

1.多态概述

某一个事物,在不同时刻表现出来的不同状态

2.多态的前提

1)有继承关系

2)有方法重写

其实没有方法重写也是可以的,但是没有意义。比如动物都有吃这个方法,但是每个具体的动物吃的实现不一样,表现出不同动物的特有属性

3)有父类引用指向子类对象 

        父类名 对象名 = new 子类名(...);

3.多态访问成员的特点

1)成员变量:编译看左,运行看左

     即编译看父类中有没有成员变量,如果有,编译不报错;运行取决于父类中的成员变量

class Fu3 {
    int num = 100;
}

class Zi3 extends Fu3 {
    int num = 1000;
}

public class PolymorphicDemo1 {
    public static void main(String[] args) {
        //多态创建一个对象
        Fu3 f = new Zi3();
        System.out.println(f.num);  //10
    }
}

2)构造方法:

     创建子类对象的时候,会先访问父类的构造方法,对父类的数据先进行初始化

3)成员方法:编译看左,运行看右

     即编译看父类中有没有成员方法,如果有,编译不报错;运行取决于子类中的成员方法

class Fu3 {
    int num = 100;

    public void show() {
        System.out.println("这是父类中的show()方法");
    }
}

class Zi3 extends Fu3 {
    int num = 1000;

    @Override
    public void show() {
        System.out.println("这是子类中的show()方法");
    }
}

public class PolymorphicDemo1 {
    public static void main(String[] args) {
        //多态创建一个对象
        Fu3 f = new Zi3();
       
        f.show();  
    }
}

4)静态成员方法:编译看左,运行看左

     由于被static修饰的成员都是与类相关的,这里不是重写(静态成员方法不能被重写),所以运行的时候,访问的还是左边

class Fu3 {
    public static void fun() {
        System.out.println("这是父类中的静态fun方法");
    }
}

class Zi3 extends Fu3 {
    public static void fun() {
        System.out.println("这是子类中的静态fun方法");
    }
}

public class PolymorphicDemo1 {
    public static void main(String[] args) {
        //多态创建一个对象
        Fu3 f = new Zi3();
        f.fun();
    }
}

4.多态的题目——”套娃“

1)看代码是否编译成功

class Fu4 {
    public void show() {
        System.out.println("fu show");
    }
}

class Zi4 extends Fu4 {
    public void show() {
        System.out.println("zi show");
    }

    public void method() {
        System.out.println("zi method");
    }
}

public class Test1 {
    public static void main(String[] args) {
        Fu4 f = new Zi4();
//        f.method();  //编译失败,父类中没有method方法
    }
}

2)看代码,输出结果

class A2{
    public void show(){
        show2();
    }

    public void show2(){
        System.out.println("我");
    }
}

class B2 extends A2{
    public void show2(){
        System.out.println("爱");
    }
}

class C2 extends B2{
    public void show(){
        super.show();
    }

    public void show2(){
        System.out.println("你");
    }
}

public class Test2 {
    public static void main(String[] args) {
        A2 a = new B2();
        a.show();  //爱。B2类中隐藏了一个show方法,实现和父类一样,是继承过去的

        B2 b = new C2();
        b.show();  //你。
    }
}

5.多态的猫狗案例

之前的方法

class Animal {
    String name;
    int age;

    Animal() {

    }

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

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

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

class Dog extends Animal {
    public Dog() {
    }

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

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

    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }
}

class Cat extends Animal {
    public Cat() {
    }

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

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

    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

public class CatDogDemo {
    public static void main(String[] args) {
        //我想养一只狗
        Dog d1 = new Dog("小白", 2);
        d1.sleep();
        d1.eat();

        //我还想养一只狗
        Dog d2 = new Dog("旺财", 3);
        d2.sleep();
        d2.eat();
     
        //我还想养一只狗
        Dog d3 = new Dog("小黑", 4);
        d3.sleep();
        d3.eat();       
}

每new完一次对象的时候,都要调用一遍eat()和sleep(),用方法改进

class Animal {
    String name;
    int age;

    Animal() {

    }

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

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

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

class Dog extends Animal {
    public Dog() {
    }

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

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

    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }
}

class Cat extends Animal {
    public Cat() {
    }

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

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

    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

public class CatDogDemo {
    public static void main(String[] args) {
        //我想养一只狗
        Dog d1 = new Dog("小白", 2);
        useDog(d1);  //用方法改进

        //我还想养一只狗
        Dog d2 = new Dog("旺财", 3);       
        useDog(d2);  //用方法改进

        //我还想养一只狗
        Dog d3 = new Dog("小黑", 4);       
        useDog(d3); 
        
        //我想养一只猫
        Cat c1 = new Cat("Tom", 2);
        useCat(c1);

        //我还想养一只猫
        Cat c2 = new Cat("奶茶", 3);
        useCat(c2);
              
    }

   //对狗的睡觉和吃饭进行调用
    public static void useDog(Dog dog){
        dog.sleep();
        dog.eat();
    }

    //对猫的睡觉和吃饭进行调用
    public static void useCat(Cat cat){
        cat.sleep();
        cat.eat();
    }

}

如果我现在不想养猫和狗了,我想养熊猫

第一步先创建这个类,第二步写一个调用熊猫吃和睡觉的方法

但是我们将来还可能养其他的动物,兔子,狮子,老虎等等

这些动物按照上面的实现都要写一个类,在测试类中写一个方法

当我的动物特别多的时候,显得特别臃肿

这时候我们用工具类改进

class Animal {
    String name;
    int age;

    Animal() {

    }

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

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

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

class Dog extends Animal {
    public Dog() {
    }

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

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

    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }
}

class Cat extends Animal {
    public Cat() {
    }

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

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

    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

class AnimalTool {
    private AnimalTool() {

    }

    //对狗的睡觉和吃饭进行调用
    public static void useDog(Dog dog){
        dog.sleep();
        dog.eat();
    }

    //对猫的睡觉和吃饭进行调用
    public static void useCat(Cat cat){
        cat.sleep();
        cat.eat();
    }
}


public class CatDogDemo {
    public static void main(String[] args) {
        //我想养一只狗
        Dog d1 = new Dog("小白", 2);
        AnimalTool.useDog(d1);  //用工具类调用
      

        //我还想养一只狗
        Dog d2 = new Dog("旺财", 3);     
        AnimalTool.useDog(d2);  //用工具类调用

        //我还想养一只狗
        Dog d3 = new Dog("小黑", 4);
        AnimalTool.useDog(d3);  //用工具类调用
     }
}

但是,工具类理论上创建以后,不能随意更改

要想养其他的动物就要往工具类加一个方法

这样虽然能实现,但是不符合规范

继续用多态改进

class Animal {
    String name;
    int age;

    Animal() {

    }

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

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

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

class Dog extends Animal {
    public Dog() {
    }

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

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

    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }
}

class Cat extends Animal {
    public Cat() {
    }

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

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

    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

class Panda extends Animal {
    public Panda() {
    }

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

    @Override
    public void sleep() {
        System.out.println("熊猫随意睡");
    }

    @Override
    public void eat() {
        System.out.println("熊猫吃竹子");
    }
}

class Tiger extends Animal {
    public Tiger() {
    }

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

    @Override
    public void sleep() {
        System.out.println("老虎躺着睡");
    }

    @Override
    public void eat() {
        System.out.println("老虎吃鸡");
    }
}

class AnimalTool {
    private AnimalTool() {

    }

    //调用的时候,相当于Animal animal = new Panda("圆圆",3)
    //Animal animal = new Dog("小白",3)
    //Animal animal = new Tiger("小虎",2)
    public static void useAnimal(Animal animal) {
        animal.sleep();
        animal.eat();
    }
    //利用二多态访问成员方法的特点,编译看左,运行看右
    //实际调用的是子类对象中的方法
}

public class CatDogDemo {
    public static void main(String[] args) {
        //我想养一只狗
        Dog d1 = new Dog("小白", 2);
        AnimalTool.useAnimal(d1);  //用多态改进

        //养一只熊猫
        Panda p2 = new Panda("圆圆", 3);
        AnimalTool.useAnimal(p2);  //用多态改进

        //养一只老虎
        Tiger t1 = new Tiger("小虎", 2);
        AnimalTool.useAnimal(t1);  //用多态改进
    }
}
     

6.多态的好处

提高了程序的维护性(由继承保证)

提高了程序的扩展性(由多态保证)

7.多态的弊端

多态无法访问父类中的方法名与子类一样的方法

不能访问子类特有的功能

8.多态中的转型问题

如果想使用子类中的特有方法,还必须使用多态,怎么办呢?

想一想之前的数据类型知识,将子类看成一个小的数据类型,将父类看成大的数据类型。我们要将大的数据类型转换成小的数据类型,之前的做法是强制类型转换。

在继承关系中,java为我们提供了一个技术给我们使用——向下转型 

将父类的引用强制转换成子类的引用

定义格式:

            子类类名 变量名 = (子类类名)父类的引用 

class Father2 {
    public void show() {
        System.out.println("这是父类中的show方法");
    }
}

class Son2 extends Father2 {
    @Override
    public void show() {
        System.out.println("这是子类中的show方法");
    }

    public void show2() {
        System.out.println("这是子类中的特有方法");
    }
}

public class PolymorphicDemo3 {
    public static void main(String[] args) {
        //多态创建对象
        Father2 f = new Son2();
//        f.show2();  报错,父类中没有show2方法

        //将父类的引用进行向下转型
        //子类类名 变量名 = (子类类名)父类的引用
        Son2 s = (Son2)f;
        s.show2();
        s.show();
    }
}

向下转型需要注意的问题:

要求转型的类和父类引用存在继承关系,并且一开始创建多态的时候,使用的是该类 

class Father2 {
    public void show() {
        System.out.println("这是父类中的show方法");
    }
}

class Son2 extends Father2 {
    @Override
    public void show() {
        System.out.println("这是子类中的show方法");
    }

    public void show2() {
        System.out.println("这是子类中的特有方法");
    }
}

class Demo extends Father2{

}

public class PolymorphicDemo3 {
    public static void main(String[] args) {
        //多态创建对象
        Father2 f = new Son2();
//        Demo d = (Demo)f;  报错
    }
}

9.向下转型的例子及内存解释

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

class Dog2 extends Animal2 {
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }

    public void lookDoor() {
        System.out.println("看门");
    }
}

class Cat2 extends Animal2 {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    public void catchMouse() {
        System.out.println("猫捉老鼠");
    }
}

public class PolymorphicDemo4 {
    public static void main(String[] args) {
        //多态的形式创建一个对象
        Animal2 a = new Dog2();
        a.eat();
//        a.lookDoor();  报错

        //向下转型访问子类中特有的方法
        Dog2 d = (Dog2) a;
        d.eat();
        d.lookDoor();

        //ClassCastException类转换异常
//        Cat2 c = (Cat2) a;  //此刻内存中是一个Dog2对象
//        c.catchMouse();
    }
}

Step1:程序先将class文件(Animal2.class,Dog2.class,Cat2.class,PolymorphicDemo4.class)加载到方法区中的class文件区。每个文件都存放着成员变量,成员方法

Step2:把每个class文件的方法加载到方法区

             Aniaml2的方法区的内容:eat()方法(假设这一部分地址值为0x005)

             Dog2的方法区的内容:eat()方法,lookDoor()方法(假设这一部分地址值为0x004)

             Cat2的方法区的内容:eat()方法,catchMouse()方法(假设这一部分地址值为0x003)

              PolymorphicDemo4的方法区的内容:(假设这一部分地址值为0x002)

             静态区:

             PolymorphicDemo4的静态区内容:静态的成员方法main()(假设这一部分地址值为0x001)

Step3:加载完毕,java虚拟机寻找到java的唯一入口main方法,去静态区中找,如果找到了将它加载到栈中去执行

Step4:读到Anamal2 a在栈中开辟空间,读到new Dog2在堆中开辟空间(里面存放着Dog2方法区的地址值0x004),(假设堆内存创建出来的对象地址值为0x0001),将地址值0x0001赋给a,a可以根据地址值找到堆内存中的这块区域

Step5:读到a.eat();,编译看左,看Animal2中有没有eat()方法,有不报错;运行看右,调用的是Dog2中的eat()方法,根据地址值0x0001找到堆内存中创建出来的Dog2对象区域,根据方法区的标记0x004找到eat()方法,把它加载到栈中来执行,执行结束,被释放,等待回收

Step6:读到a.lookDoor();,编译看左,看Animal2中有没有lookDoor()方法,没有报错

Step7:读到Dog2 d在栈中开辟空间,把a的地址值0x0001赋给它

Step8:读到d.eat();,根据地址值0x0001找到堆内存中创建出来的Dog2对象区域,根据方法区的标记0x004找到eat()方法,把它加载到栈中来执行,执行结束,被释放,等待回收

Step8:读到d.lookDoor();,根据地址值0x0001找到堆内存中创建出来的Dog2对象区域,根据方法区的标记0x004找到eat()方法,把它加载到栈中来执行,执行结束,被释放,等待回收

Step7:读到Cat2 c在栈中开辟空间,把a的地址值0x0001赋给它,

             c是Cat2类型的,a是Dog2类型的,它俩之间不存在继承关系,也不是父类引用指向子类对象,报错

10.多态的练习

不同地方饮食文化与习惯的区别

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

class SouthPerson extends Person {
    @Override
    public void eat() {
        System.out.println("南方人吃米饭");
    }

    public void playMaJiang(){
        System.out.println("南方人打麻将");
    }
}

class NorthPerson extends Person{
    @Override
    public void eat() {
        System.out.println("北方人吃面食");
    }

    public void bath(){
        System.out.println("北方人搓澡");
    }
}

public class PolymorphicDemo5 {
    public static void main(String[] args) {
        //多态创建南方人对象
        Person p = new SouthPerson();
        p.eat();
//        p.playMaJiang();  //报错
        //向下转型
        SouthPerson sp = (SouthPerson)p;
        sp.playMaJiang();

        //多态创建北方人对象
        Person p2 = new NorthPerson();
        p2.eat();
//        p2.bath();  //报错
        //向下转型
        NorthPerson np = (NorthPerson)p2;
        np.bath();
    }
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

+7_big data

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值