飞道的博客

JAVA基础篇008-对象初始化过程、对象调用成员过程

399人阅读  评论(0)

目录

一、对象初始化过程

1、示例代码

2、分析

3、总结

二、对象调用成员的过程

1、代码示例

2、分析

3、总结


一、对象初始化过程

1、示例代码

给出如下代码,请问一共有几条打印语句,分别是什么?


  
  1. public class ObjectInitialization {
  2. public static void main(String[] args) {
  3. Person p1 = new Person( "百里", 18);
  4. System.out.println( "------------------------");
  5. Person p2 = new Person( "慕溪", 18);
  6. }
  7. }
  8. class Person{
  9. //成员变量(实例变量)
  10. private String name;
  11. private int age = 20;
  12. //静态成员变量(类变量)
  13. private static String country = "cn";
  14. //静态代码块
  15. static{
  16. System.out.println( "Staic Block...country ="+country);
  17. }
  18. //构造代码块
  19. {
  20. System.out.println( "Construction Block...name ="+name+ ", age ="+age+ ", country ="+country);
  21. }
  22. //构造函数
  23. Person(String name, int age){
  24. this.name =name;
  25. this.age =age;
  26. System.out.println( "Construction Function...name ="+name+ ", age ="+age+ ", country ="+country);
  27. }
  28. }

输出如下:

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、代码示例


  
  1. class Person{
  2. private String name;
  3. private int age = 20;
  4. private static String country= "cn";
  5. Person(String name, int age){
  6. this.name =name;
  7. this.age =age;
  8. }
  9. public void speak(){
  10. System.out.println( this.name + "..."+ this.age);
  11. }
  12. public void setName(String name){
  13. this.name =name;
  14. }
  15. public static void showCountry(){
  16. System.out.println( "country ="+ country);
  17. method();
  18. }
  19. public static void method(){
  20. System.out.println( "static method is running");
  21. }
  22. }
  23. class Test{
  24. public static void main(String[] args) {
  25. Person p = new Person( "Benjamin", 28);
  26. p.setName( "ZXM");
  27. Person.showCountry();
  28. }
  29. }

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() 开辟了一个局部变量对应的内存空间。


  
  1. public static void showCountry(){
  2. System.out.println( "country ="+ country);
  3. method();
  4. }

PS:如上代码 showCountry() 中调用了method();这个method() 前面有省略的东西么?一定有!因为只要是方法执行了,一定是被调用了,必须先调用,后执行。
静态方法之间相互访问,如果写成直接访问,那省略的一定是“类名.”,如下:


  
  1. public static void showCountry(){
  2. System.out.println( "country ="+ country);
  3. Person.method();
  4. }

3、总结

1、非静态成员方法直接访问其他非静态成员,省略的是"this.";
2、静态成员方法直接访问其他的静态成员,省略的是"类名.";
3、代码和代码中使用到的数据是相对独立的内存区域。

另:JAVA基础篇006-什么是类变量、实例变量、以及区别

每天记录一个小知识,分享是一种快乐,点赞是一种美德!


转载:https://blog.csdn.net/duoyu779553/article/details/105958597
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场