java中多态的实现机制

Wesley13
• 阅读 569

多态的概念:

  简单来说就是事物在运行过程中存在的不同状态,即父类或接口定义的引用变量指向子类或具体实现类的实例对象。程序调用方法在运行期才进行动态绑定,而不是引用变量的类型中定义的方法。

多态存在的前提:

1、存在继承关系,子类继承父类;

2、子类重写父类的方法;

3、父类引用指向子类对象。

具体实例:

1、定义一个父类:Animal

 1 package demo;
 2 
 3  class Animal{
 4          int num = 10;
 5      static int age = 20; 
 6          public void eat() {
 7          System.out.println("动物吃饭");
 8      }  
 9          public static void sleep() {
10          System.out.println("动物睡觉");
11      }
12          public void run() {
13          System.out.println("动物奔跑");
14      }
15  }

2、子类:Cat继承Animal

 1 package demo;
 2 
 3 public class Cat extends Animal{
 4     int num=80;
 5     static int age=90;
 6     String name="TomCat";
 7     @Override
 8     public void eat() {
 9         // TODO Auto-generated method stub
10         System.out.println("猫吃饭");
11     }
12     public static void sleep(){
13         System.out.println("猫在睡觉");
14     }
15     public void catchMouse() {
16         // TODO Auto-generated method stub
17         System.out.println("猫抓老鼠");
18     }
19 }

3、测试类:Test1

 1 package demo;
 2 
 3 public class Test1 {
 4 
 5     public static void main(String[] args) {
 6         Animal am=new Cat();
 7         am.eat();
 8         am.sleep();
 9         am.run();
10         System.out.println(am.num);
11         System.out.println(am.age);
12         //以下两行注释内容稍后解释
13         //am.catchMouse();
14         //System.out.println(am.name);
15     }
16 
17 }

以上三段代码充分体现了多态存在的前提条件:

1、存在继承关系:Cat 类继承了Animal类;

2、子类要重写父类方法:子类Cat重写(override)了父类Animal的两个方法eat(),sleep(),其中eat()为普通方法,sleep()为静态方法(static);

3、父类引用指向子类对象:测试类中Animal am=new Cat();,语句在堆内开辟了一块内存分配给子类(Cat),并把栈内存中的父类(Animal)的引用指向了这个Cat对象。

测试类运行后的结果:

java中多态的实现机制

可以看出:

1、子类Cat重写的父类Animal的普通方法eat()的输出结果为“猫吃饭”;

2、子类Cat重写的父类Animal的静态方法sleep()的输出结果为“动物睡觉”;

3、未被子类Cat重写的父类Animal的普通方法run()的输出结果为“动物奔跑”;

4、子类Cat继承的父类Animal属性,输出结果分别为父类属性;

5、输出子类Cat特有属性和方法则会报错。

因此,根据以上分析可以总结出多态成员访问的特点:

Animal am=new Cat();

成员变量:

编译看左(父类),运行看左(父类);

成员方法:

编译看左(父类),运行看右(子类),输入动态绑定;

静态方法:

编译看左(父类),运行看左(父类),静态方法被提升到类级别,算不上重写,所以访问还是看父类;

多态以后不能使用子类特有的属性和方法,在子类Cat中有一个特有的属性String name="TomCat";并且还有一个特有的抓老鼠的方法catchMouse()。但是在测试类Test1中,尝试调用子类的特有方法和打印子类特有的属性时,就会报错。

java中多态的实现机制

  那么如果想要使用子类特有的属性和方法该怎么办呢?可以把这个父类引用指向的子类对象强制转换为子类Cat类型,这样am就是子类Cat类型的引用,指向的也是Cat对象了,这样就能够使用子类的一些属性和方法了。

 1 package demo;
 2 
 3 public class Test1 {
 4 
 5     public static void main(String[] args) {
 6         Animal am=new Cat();
 7         am.eat();
 8         am.sleep();
 9         am.run();
10         System.out.println(am.num);
11         System.out.println(am.age);
12         //以下两行注释内容稍后解释
13         //am.catchMouse();
14         //System.out.println(am.name);
15         System.out.println("-------------------------");
16         Cat ct=(Cat)am;
17         ct.eat();
18         ct.sleep();
19         ct.run();
20         ct.catchMouse();
21         System.out.println(ct.num);
22         System.out.println(ct.age);
23         System.out.println(ct.name);
24     }
25 
26 }

java中多态的实现机制

  执行强转语句Cat ct=(Cat)am;后,ct就指向了最开始在堆内存中创建的那个Cat对象了。这就是多态的功能,使用起来十分的灵活,觉少了多余对象的创建,不用为了使用子类的某个方法再去堆内存中开辟一块新的空间给一个新的子类对象了。

花木兰替父从军的例子:

大家都知道花木兰替父从军的例子,花木兰替父亲花弧从军。那么这时候花木兰是子类,花弧是父类。花弧有自己的成员属性年龄,姓名,性别。花木兰也有这些属性,但是很明显二者的属性值完全不一样。花弧有自己的非静态成员方法‘骑马杀敌’,同样花木兰也遗传了父亲一样的方法‘骑马杀敌’。花弧还有一个静态方法‘自我介绍’,每个人都可以问花弧姓甚名谁。同时花木兰还有一个自己特有的非静态成员方法‘涂脂抹粉’。但是,现在花木兰替父从军,女扮男装。这时候相当于父类的引用(花弧这个名字)指向了子类对象(花木兰这个人),那么在其他类(其他的人)中访问子类对象(花木兰这个人)的成员属性(姓名,年龄,性别)时,其实看到的都是花木兰她父亲的名字(花弧)、年龄(60岁)、性别(男)。当访问子类对象(花木兰这个人)的非静态成员方法(骑马打仗)时,其实都是看到花木兰自己运用十八般武艺在骑马打仗。当访问花木兰的静态方法时(自我介绍),花木兰都是用她父亲的名字信息在向别人作自我介绍。并且这时候花木兰不能使用自己特有的成员方法‘涂脂抹粉’。-----多态中的向上转型

那么终于一将功成万骨枯,打仗旗开得胜了,花木兰告别了战争生活。有一天,遇到了自己心爱的男人,这时候爱情的力量将父类对象的引用(花弧这个名字)强制转换为子类对象本来的引用(花木兰这个名字),那么花木兰又从新成为了她自己,这时候她完全是她自己了。名字是花木兰,年龄是28,性别是女,打仗依然那样生猛女汉子,自我介绍则堂堂正正地告诉别人我叫花木兰。终于可以使用自己特有的成员方法‘涂脂抹粉’了。从此,花木兰完全回到了替父从军前的那个花木兰了。-----多态中的向下转型

向上转型向下转型一定是在多态这个前提下,同时向上转型是安全的,向下转型则不安全。比如强制将女儿变成父亲,则女儿可以使用父亲的身份存在,反之,将父亲变成女儿,就变成东方不败了,系统此时就会报错非法类型转换。另外开发中一般利用多态声明形式参数,并将创建子类的匿名对象作为实际参数。

点赞
收藏
评论区
推荐文章
Jacquelyn38 Jacquelyn38
2年前
你不可不知的JS面试题(第二期)
1、什么是继承?子类可以使用父类的所有功能,并且对功能进行扩展。新增方法改用方法(1)、ES6使用extends子类继承父类的方法。// 父类    class A        constructor(name)            this.name name;                getNa
Wesley13 Wesley13
2年前
java中面向对象的一点学习总结
最近开始看java的一些东西,感觉比python麻烦些,今天学习了面向对象的一些东西,觉得挺多挺复杂,这里做个知识总结以一个简单的例子来说明java面向对象的三大特性,封装,继承,多态,有一个动物(Animal)基类,定义了run与eat方法,然后有一个猫(Cat)与狗(Dog)的子类继承了动物这个父类,子类重写(override)了父类的run与eat
Wesley13 Wesley13
2年前
java面试(1)
1.面向对象的基本特征  封装、继承、多态、  封装:把客观事物封装成类  继承:继承一个类,就可以使用这个类的所有功能,并且在无需编写原来类的情况下对这些功能进行扩展  多态:子对象调用父对象,父对象会根据当前调用的子对象以不同的方式运作  实现多态:覆盖,重载2.final\\finally\\finalize的区别  fin
Wesley13 Wesley13
2年前
java向上转型和向下转型1
  在java继承体系中,认为父类(超类)在上层,子类在下层(派生类),向上转型就是把子类对象转成父类对象。1publicclassFather{2publicvoideat(){3System.out.println("我是父类的方法吃。。。。。");4}
待兔 待兔
3年前
Java多态实现原理
Java多态概述多态是面向对象编程语言的重要特性,它允许基类的指针或引用指向派生类的对象,而在具体访问时实现方法的动态绑定。Java对于方法调用动态绑定的实现主要依赖于方法表,但通过类引用调用(invokevirtual)和接口引用调用(invokeinterface)的实现则有所不同。类引用调用的大致过程为:Java编译器将Java源代码编译成c
Stella981 Stella981
2年前
Python Day24:类的继承、派生、覆盖、super()、绑定、非绑定方法
类的继承、派生、覆盖、super()python类的继承:子类继承父类,只需要在定义类的时候在类名后面加上(父类名)。继承之后,父类的属性方法、子类都可以访问派生:子类继承父类后,自己在父类的基础上,又添加了一些属于自己特性的属性、方法
Wesley13 Wesley13
2年前
Java的类继承
知识点1、继承作用:提高代码的重用性,继承之后子类可以继承父类中的属性和方法减少重复代码条件:子类和父类要满足isa的逻辑关系,才能使用继承。如:苹果isa水果语法:使用extends连接子类和父类。子类extends父类Java是单继承,一个类只能继承一个父类。子类不能继承父类私有的属性,但是可以
Wesley13 Wesley13
2年前
Java基础学习总结(8)——super关键字
一、super关键字  在JAVA类中使用super来引用父类的成分,用this来引用当前对象,如果一个类从另外一个类继承,我们new这个子类的实例对象的时候,这个子类对象里面会有一个父类对象。怎么去引用里面的父类对象呢?使用super来引用,this指的是当前对象的引用,super是当前对象里面的父对象的引用。
Wesley13 Wesley13
2年前
Java基础28
1/2继承的概述:31.提高了代码复用性,简化了代码42.让类与类之间产生了继承关系,才有了后面的多态特性的存在5注意:千万不要为了获取其他类的功能简化代码,而建立继承关系,必须要类与类之间存在继承关系,继承关系:isa67子类拥有父类的成员,子类不能拥有父类
Stella981 Stella981
2年前
Socket与系统调用深度分析
Socket与系统调用深度分析实验环境:Linux5.0.1内核32位系统的MenuOS本文主要解决两个问题用户态如何通过中断进入socket的系统调用socket抽象层如何通过多态的机制,来支持不同的传输层的协议。也就是socket作为父类,TCP/UDP为子类,父类指向子类对象,实现多态