目录
一、对象初始化过程
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、代码和代码中使用到的数据是相对独立的内存区域。
每天记录一个小知识,分享是一种快乐,点赞是一种美德!