1.首先去检查这个指令的参数是否能 在常量池中能否定位到一个类的符号引用,即验证是否是第一次使用该类。如果没有(不是第一次使用),那必须先执行相应的类加载过程(class.forname())。
2.类加载后为要创建的对象分配内存。把一块确定大小的内存从Java堆中划分出来,目前常用的有两种方式(指针碰撞和空闲列表)。
( 2.1. 指针碰撞(Bump the Pointer):假设Java堆的内存是绝对规整的,所有用过的内存都放一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅把那个指针向空闲空间那边挪动一段与对象大小相等的距离。 2.2. 空闲列表(Free List):如果Java堆中的内存并不是规整的,已使用的内存和空间的内存是相互交错的,虚拟机必须维护一个空闲列表,记录上哪些内存块是可用的,在分配时候从列表中找到一块足够大的空间划分给对象使用。)
3.内存分配完后,虚拟机需要将分配到的内存空间中的数据类型都 初始化为零值(不包括对象头)
1.分配内存空间的动作进行同步处理 :实际上虚拟机采用CAS配上失败重试的方式保证了更新操作的原子性。
2.内存分配的动作按照线程划分在不同的空间中进行: 为每个线程在Java堆中预先分配一小块内存 ,称为本地线程分配缓冲(Thread Local Allocation Buffer, TLAB)
4.虚拟机要 对对象头进行必要的设置 ,例如这个对象是哪个类的实例(即所属类)、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息,这些信息都存放在对象的对象头中。
5.调用对象的init()方法 ,根据传入的属性值给对象属性赋值。
6.在线程 栈中新建对象引用 ,并指向堆中刚刚新建的对象实
父类 f= new 子类(); 这条语句包含了三个部分:
创建对象 ——new 子类(); 用new操作符创建了一个对象(实例化),且相应的构造方法被调用;新创建的对象在内存中被分配空间。它们可以通过引用变量来访问.
声明对象引用变量 ——父类 f;
本质上来说,一个类是一个程序员定义的类型。类是一种引用类型,这意味着该类类型的变量都可以引用该类的一个实例(即实例化对象)。实例对象的数据和方法可以运用点操作符(.)通过对象的引用变量进行访问。
将对象的引用赋值给这个引用变量——f = new 子类();
public class F {
int num=1;
public void addF(){
num++;
System.out.println(num);
}
}
class Z extends F{
int num=2;
public void addF(){
num++;
System.out.println(num);
}
}
class Test{
public static void main(String[] args) {
F f =new Z();
f.addF();
System.out.println(f.num);
}
}
由上述代码显示可以看出,当继承时子类和父类中出现同名成员变量时,同名变量之间相互独立;如果是直接获取时只需依据对象类型即可;如果进行调用时依据方法定义在哪个类中,父类中进行父类调用,子类中进行子类调用。
说明是存了两个值 一个父类的 一个子类的 子类重写了就会调用子类的方法,使用的还是子类的值 因为方法区是共享的,所以这些值肯定都是定义在了堆里
https://blog.csdn.net/qq_45768060/article/details/105490189
https://www.cnblogs.com/gjmhome/p/11401397.html
https://www.cnblogs.com/efforts-will-be-lucky/p/7118685.html
https://www.cnblogs.com/jiading/articles/12559998.html
https://blog.csdn.net/youngyouth/article/details/79933612
|