JavaSE--重新学习_查漏补缺(4)--普通类、子类在JVM内存中的实例化过程_对象编译时和运行时类型_Sting对象不同的创建方式_多态性本质_子类继承父类注意到
文章目录
一、简单类对象的实例化过程(JVM内存解析)
- 1、普通无继承类的对象实例化过程
-
- (1)在方法区加载需要实例化对象的类。
-
- (2)在栈中申请空间,声明接收对象的变量,分配栈内存地址,如下图中的p。
-
- (3)在堆内存中申请开辟空间,分配堆内存地址。
-
- (4)在对象空间,对对象中的属性进行默认初始化。若类成员变量赋有初值,则显示初始化。
-
- (5)构造函数方法进栈,进行初始化。
-
- (6)初始化完毕后,将堆内存中的地址的地址赋给引用变量(本例中即 p),构造方法出栈。
- (6)初始化完毕后,将堆内存中的地址的地址赋给引用变量(本例中即 p),构造方法出栈。
二、子类对象的实例化过程(JVM内存解析)
- 1、普通无继承类的对象实例化过程
-
- (1)在方法区加载需要实例化对象的类,先加载父类,后加载子类。
-
- (2)在栈中申请空间,声明接收对象的变量,分配栈内存地址,如下图中的stu。
-
- (3)在堆内存中申请开辟空间,分配堆内存地址。
-
- (4)在对象空间,对对象中的属性(包括父类的属性)进行默认初始化。若类成员变量赋有初值,然后显示初始化父类属性->显示初始化子类属性。
-
- (5)子类构造函数方法进栈。
-
- (6)若父类成员变量赋有初值,则显示初始化父类的属性。
-
- (7)父类构造函数方法进栈,执行完毕出栈。(栈后进先出)
-
- (8)若子类成员变量赋有初值,则显示初始化父类的属性。
-
- (9)初始化完毕后,将堆内存中的地址的地址赋给引用变量(本例中即 stu),子类构造方法出栈。
- (9)初始化完毕后,将堆内存中的地址的地址赋给引用变量(本例中即 stu),子类构造方法出栈。
三、String对象不同的创建方式
- 1、字面量创建Sring对象
- 2、new创建String对象
字面量创建对象的时候,只在常量池创建一个对象,如s1、s2共同引用一个常量池的对象;
new的时候,常量池有对象,堆内存也要有对象,如s3,s4共同引用一个常量池的对象,还要各种创建对象;
所以字面量方法要比new省内存。
四、对象实例化在编译时类型和运行时类型问题
- 若是父类类型变量引用子类构造方法实例化时,在编译时该父类类型的变量是父类类型;在运行时该该父类类型的变量承载了子类的对象,结合上面堆栈内存解析1可知,此时类型的变量就是子类的对象。
如:
Map<String,String> map = new HashMap();
程序运行时map是HashMap对象。
(解析1:因为运行时 会在堆中创建new HashMap(),然后new HashMap()再指回map 在栈的内存,此时map引用的HashMap()类的对象,即时map编译时HashMap对象。)
这里也对象的多态性有关,如下:
五、多态性本质
- 1、编译时类型和运行时类型不一致,就出现多态。
- 体现:
-
- 方法的重载和重写。
-
- 抽象类和接口的实现。
- 抽象类和接口的实现。
- 2、一个引用类型变量如果声明为父类类型,但实质引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法,即父类没有的,因为编译时会出错,编译器会认为该父类类型变量就是父类类型,父类没有的属性和方法,不能调用。
- 3、一个引用类型变量如果声明为父类类型,但实质引用的是子类对象,父类子类都有一个共同的方法,编译时该父类类型变量为父类类型,而方法的调用时运行时确定的,所以调用的是子类中同名方法–动态绑定。
以上也可称为虚拟方法调用。
六、子类继承父类注意点
- 子类在重写父类方法时,意味子类里的定义的方法覆盖了父类里的同名方法。
- 子类和父类有完全相同的实例变量,子类的实例变量依然不可能覆盖父类中定义的实例变量。
=====================================================
说到多态性,顺便说下面对对象的四大特征
不是说三大吗,怎么就四大了呢,其实除了 封装,继承,多态,还可以说一种就是 抽象。