目录
一、对象初始化过程
1、示例代码
给出如下代码,请问一共有几条打印语句,分别是什么?
-
public
class ObjectInitialization {
-
public static void main(String[] args) {
-
Person p1 =
new Person(
"百里",
18);
-
System.out.println(
"------------------------");
-
Person p2 =
new Person(
"慕溪",
18);
-
}
-
}
-
class Person{
-
//成员变量(实例变量)
-
private String name;
-
private
int age =
20;
-
//静态成员变量(类变量)
-
private
static String country =
"cn";
-
//静态代码块
-
static{
-
System.out.println(
"Staic Block...country ="+country);
-
}
-
//构造代码块
-
{
-
System.out.println(
"Construction Block...name ="+name+
", age ="+age+
", country ="+country);
-
}
-
//构造函数
-
Person(String name,
int age){
-
this.name =name;
-
this.age =age;
-
System.out.println(
"Construction Function...name ="+name+
", age ="+age+
", country ="+country);
-
}
-
}
输出如下:
2、分析
Person p1 =new Person("百里", 18); 这句代码一执行,都做了什么事情?
1、因为 new 的时候用到了 Person 类的构造方法,所以类文件 Person.class 会被加载到内存中;
2、为静态成员变量(country)在方法区中开辟内存空间,并做如下初始化:
|-先为静态成员 country 进行默认初始化,初始化值为 null;
|-再为静态成员 country 进行显式初始化,初始化值为 cn;
3、执行 Person 类的静态代码块,并输出 Staic Block...country =cn;
4、OS 在堆内存中开辟空间,为 Person 类的对象分配内存地址;
5、在堆内存中建立成员变量,并进行如下初始化:
|-先进行默认初始化:name 默认初始化为 null,age 默认初始化为0;
|-再进行显式初始化:age 显式初始化为18;
6、构造代码块初始化,此处打印出:Construction Block...name =null, age =20, country =cn
7、构造函数初始化,name 和 age 分别显式初始化为"百里"和18, 并且打印出:Construction Function...name =百里, age =18, country =cn
8、将对象在堆内存中的首地址赋值给栈内存中的 Person 类的引用变量p1。
PS:为什么执行 Person p2 =new Person("慕溪", 18); 这句代码的时候没有输出 Staic Block...country =cn;
3、总结
在调用一个类的构造方法进行对象的创建的时候,进行的动作如下:
1.为类中静态成员变量(类变量)初始化,先默认初始化,再显式初始化;
2.执行类中的静态代码块为类初始化;
PS:前两步是可选的,只有当类中存在静态成员变量和静态代码块时,才对应执行前面两步,两者都是当类加载到内存时执行,并且仅仅执行一次!
3.为实例变量进行初始化,先默认初始化,再显式初始化;
4.执行类中构造代码块为该对象进行公共初始化;
5.执行构造函数为该对象进行特定初始化。
二、对象调用成员的过程
1、代码示例
-
class Person{
-
private String name;
-
private
int age =
20;
-
private
static String country=
"cn";
-
-
Person(String name,
int age){
-
this.name =name;
-
this.age =age;
-
}
-
-
public void speak(){
-
System.out.println(
this.name +
"..."+
this.age);
-
}
-
-
public void setName(String name){
-
this.name =name;
-
}
-
-
public static void showCountry(){
-
System.out.println(
"country ="+ country);
-
method();
-
}
-
-
public static void method(){
-
System.out.println(
"static method is running");
-
}
-
}
-
-
class Test{
-
public static void main(String[] args) {
-
Person p =
new Person(
"Benjamin",
28);
-
p.setName(
"ZXM");
-
Person.showCountry();
-
}
-
}
2、分析
main 方法执行每一句代码,内存变化过程如下:
1、对象初始化过程在前面,并且在栈内存中,为 main 方法开辟了方法中局部变量的内存空间,此时 Person 类引用变量 p 指向堆内存中的 Person 类对象,name 值为 Benjamin,age 值为20;
2、执行 p.setName("ZXM"):
首先 OS 在栈内存中为 setName() 方法开辟了局部变量的内存空间,并且形参 name 接受 main 方法中传入的实参,初始化为ZXM;由于 setName() 为非静态方法,并且调用了该对象的另一个非静态成员,所以这个 name 成员所属的对象就是 this;这个 this 就是在主方法中调用 setName() 方法的对象p;因此 setName() 中的 this 指向堆内存中的那个对象,p.setName(“ZXM”) 相当于将p的值赋值给了 this,每一个非静态方法中都有一个 this 变量;执行完之后,栈内存的 setName() 中对应的临时变量 name 和引用变量 this 全部释放。
3、执行到 Person.showCountry():
这是个静态方法,在栈内存中开辟了临时变量的内存空间,注意:静态方法中是没有 this 的! 此时调用的静态变量 country 并没有经过堆内存,而是经过方法区中的 country,值为cn。
4、静态方法 showCountry() 中又调用了另一个静态方法 method(),此时在栈内存中也为 method() 开辟了一个局部变量对应的内存空间。
-
public static void showCountry(){
-
System.out.println(
"country ="+ country);
-
method();
-
}
PS:如上代码 showCountry() 中调用了method();这个method() 前面有省略的东西么?一定有!因为只要是方法执行了,一定是被调用了,必须先调用,后执行。
静态方法之间相互访问,如果写成直接访问,那省略的一定是“类名.”,如下:
-
public static void showCountry(){
-
System.out.println(
"country ="+ country);
-
Person.method();
-
}
3、总结
1、非静态成员方法直接访问其他非静态成员,省略的是"this.";
2、静态成员方法直接访问其他的静态成员,省略的是"类名.";
3、代码和代码中使用到的数据是相对独立的内存区域。
每天记录一个小知识,分享是一种快乐,点赞是一种美德!
转载:https://blog.csdn.net/duoyu779553/article/details/105958597