在这里举个例子,比如我们有以下代码:
class Person{ int age=90; String name; public Person(String n, int a) { this.age = age; this.name = name; } }
此时呢,我们去new一个对象:Person p = new Person("帅哥",23);
在创建这个对象的过程中,会发生什么?这种对象的创建流程,也是面试官会问到的东西
首先, 当我们创建这个类的时候,会先去加载这个Person类,第一个动作就是在方法区加载Person类信息,也就是我们的class Person这段代码。加载完了之后,就开始创建空间,new的会后,在堆里面开辟一个空间,这个空间就会有一个地址,我们就随便写一下,比如这个地址是0x1122,开完了这个空间之后,里面会有2个空间,一个是存放age,一个是存放name。
然后接下来就是进行初始化,这一步是默认初始化,也就是不会去赋值,默认初始化,此时age的默认值是0,而name是String类型,默认值就是null。也就是说在开辟空间的时候,会有一个默认值,age是0,而name就是null。
初始化之后再看一开始的赋值,age是90,name还是null,这一步是显式的初始化,显式的初始化就是看一开始赋值是多少,是90,那么这时候就0就变成了90,而name没有显式的值,就不用去动。
而当我们初始化做完了之后,才会发现这里还有一个构造器的处理,这个时候构造器才开始执行,构造器是完成属性的初始化,而不是创建对象。
Person p = new Person("帅哥",23);
public Person(String n, int a) {
this.name = n;
this.age = a;
}
这时候就会把帅哥这个实参传给n,再通过n传给name属性,此时会把name的null变成帅哥,而这个"帅哥"是在常量池里,这个地方也会有一个地址,比如说这个地址是0x1133,然后之前的name值是null,此时是0x1133,这时候0x1133就指向常量池的0x1133所对应的"帅哥",然后再把20这个实参赋给了形参,这个时候age又变成了20。也就是到这里,new就已经做完了。
我们在分配空间的时候,有0x1122这个地址,此时此刻它才把0x1122返回给p,然后这个p才指向这个地址空间。
对象是在堆里的,那里面才是真正的对象,就像真正的人一样,而p只是对象的引用而已,可以这么理解,有个人叫张三,而这边有个人,那么这个人到底是谁?张三这个名字是个人吗?真正的人是右边的这个小人,他还可以改名,而张三就可以是前面讲的p,可以随时改名,而这个人才是在堆里面开的空间。
还有这么一种情况,Person p2 = p; 这是种什么情况呢?
就是说p2是个新的对象的引用,p2的地址会把p的地址拷贝过来,也是0x1122,此时也是指向堆里面的0x1122,也就是说在堆里面的对象有2个对象引用,就好比说一个孩子小时候有一个名字叫小张三,长大了叫大张三,但本质还是同一个人。
最后总结一下流程: