首页 > 学院 > 开发设计 > 正文

【Java】java多态的理解

2019-11-14 09:19:03
字体:
来源:转载
供稿:网友

首先简要说明下程序运行时,内存的结构。堆区栈区,常量区,静态方法区和非静态方法区。 1.栈:存放基本类型的变量数据和对象的引用(也就是在new对象时左边那一块),但是对象本身不放在栈中,而是存在堆(new出来的对象)。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会消失。 2.堆:存放new出来的对象。堆中的对象由垃圾回收器负责回收,因此大小和生命周期不需要确定。 3.常量区:存放字符串常量和基本类型常量。

代码示例:

class Fu{ void method1() { System.out.PRintln("fu method_1"); } void method2() { System.out.println("fu method_2"); } static void method3() { System.out.println("fu method_3"); }}class Zi extends Fu{ void method1() { System.out.println("zi method_1"); } void method4() { System.out.println("zi method_4"); } static void method3() { System.out.println("fu method_3"); }}class DemoDuotai{ public static void main(String args[]) { Fu aa=new Zi();//创建一个父类引用,指向子类。 aa.method1();//发生动态绑定,打印子的 aa.method3();//打印父的 }}

内存图简要示例 这里写图片描述

分析

aa.method1()-->this.method1()-->(new Zi()).method1()我们知道类的非静态成员函数,需要类对象来调用。aa是指向Zi类的对象,method1()在运行时一定是被对象调用执行,因为他打印的时候或者访问的时候是访问对象中的那些数据。而静态方法就不同了,他本身不访问对象特有数据。当Fu类和Zi类被加载到内存的时候,静态方法区就已经在里面啦,并且绑定在类上,所以可以直接采用类名调用,也就是所谓的静态绑定。他找的是静态区的方法,不参考右边的对象。所以aa.method3();只参考这个引用型变量aa是哪个类的。

总结

编译时期:参考应用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有,编译失败。运行时期:参考对象(new出来的对象)所属的类中是否有调用的方法。(动态绑定)。多态中,成员变量的特点:无聊编译运行,都参考左边(引用型变量所属的类)。多态中,静态函数的特点:无聊编译运行,都参考左边。(静态绑定)

java编译和运行时的区别

举个例子来说明编译时(javac)和运行时(java)的区别,代码如下:

class Demo{ private int num; Demo(int num) { this.num=num; } public boolean equals(Object d) { Demo a=(Demo)d; return this.num==a.num; }}class Person{}public class object_equals{ public static void main(String[] args) { Demo a=new Demo(3); Demo b=new Demo(4); Person c=new Person(); System.out.println(a.equals(c)); }}

结果:编译通过,运行挂掉

分析:equals方法是超类Object中的方法,我们把他复写,调用equals时,参数 Object d=new Person()这里发生了向上转型,接着Demo a=(Demo)d 编译的时候是不会出错的,因为此处的d引用变量是绑定的Object这个类;而运行时,发生动态绑定也就绑定到了Person类上,把Person类的对象转化成Demo类的对象,出现类型转换错误。

改正:加上以下判断即可.

if(!d instanceof Demo) return ;
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表