【Java】java多态的理解
2017-02-05 19:22
239 查看
首先简要说明下程序运行时,内存的结构。堆区栈区,常量区,静态方法区和非静态方法区。
1.栈:存放基本类型的变量数据和对象的引用(也就是在new对象时左边那一块),但是对象本身不放在栈中,而是存在堆(new出来的对象)。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会消失。
2.堆:存放new出来的对象。堆中的对象由垃圾回收器负责回收,因此大小和生命周期不需要确定。
3.常量区:存放字符串常量和基本类型常量。
代码示例:
内存图简要示例
![](https://img-blog.csdn.net/20170205190441189?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcTMyODk2NTUzOQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
我们知道类的非静态成员函数,需要类对象来调用。aa是指向Zi类的对象,method1()在运行时一定是被对象调用执行,因为他打印的时候或者访问的时候是访问对象中的那些数据。
而静态方法就不同了,他本身不访问对象特有数据。当Fu类和Zi类被加载到内存的时候,静态方法区就已经在里面啦,并且绑定在类上,所以可以直接采用类名调用,也就是所谓的静态绑定。他找的是静态区的方法,不参考右边的对象。所以aa.method3();只参考这个引用型变量aa是哪个类的。
运行时期:参考对象(new出来的对象)所属的类中是否有调用的方法。(动态绑定)。
多态中,成员变量的特点:无聊编译运行,都参考左边(引用型变量所属的类)。
多态中,静态函数的特点:无聊编译运行,都参考左边。(静态绑定)
结果:编译通过,运行挂掉
分析:equals方法是超类Object中的方法,我们把他复写,调用equals时,参数 Object d=new Person()这里发生了向上转型,接着Demo a=(Demo)d 编译的时候是不会出错的,因为此处的d引用变量是绑定的Object这个类;而运行时,发生动态绑定也就绑定到了Person类上,把Person类的对象转化成Demo类的对象,出现类型转换错误。
改正:加上以下判断即可.
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 ;
相关文章推荐
- java设计模式之组合模式
- MyEclipse2014安装图解
- Javaweb程序服务器部署_2
- Javaweb程序服务器部署_1
- 关于java各种包下载地址
- struts2国际化--你知道LocalizedTextUtil吗?
- Javaweb程序服务器部署_0
- JSON 字符串 与 java 对象的转换
- Springmvc---数据回显
- 【Java】java static标识符引发的思考
- Javaweb程序服务器部署
- java枚举到底是什么鬼?
- JavaWeb_反射_0
- java日志系统-- slf4j + log4j
- JavaWeb_反射
- java浅析
- eclipse用genymotion作为安卓模拟器 遇到的问题
- 编译Java-cef
- Java中的文件和目录管理----Path、Files
- Java自动装箱与拆箱