• Java笔记(十二)……类中各部分加载顺序及存放位置问题


    什么时候会加载类

    使用到类中的内容时加载,三种情况:

    • 创建对象:new StaticDemo();
    • 使用类中的静态成员:StaticCode.num = 9;  StaticCode.getNum();
    • 在命令行中运行:java StaticDemo

    类所有内容加载顺序及内存中的存储位置

    语句分析

    Person p = new Person(“Shawn”,20);

    1. 在栈内存中,开辟main函数的空间,建立main函数的变量p。
    2. 加载类文件:因为new要用到Person.class,所以要先从硬盘中找到Person.class类文件,并加载到内存中。
      • 加载类文件时,除了非静态成员变量不会被加载,其他的都会被加载。
      • 静态成员变量(类变量)------>方法区的非静态部分
      • 静态方法------>方法区的静态部分
      • 静态代码块------>方法区的静态部分
      • 构造代码块------>方法区的静态部分
      • 注意:在Person.class文件加载时,静态方法和非静态方法都会被加载到方法区中,只不过要调用非静态方法时需要先实例化一个对象,对象才能调用非静态方法。如果让类中所有的非静态方法都随着对象的实例化而建立一次,那么会大量消耗内存资源,所以才会让所有对象共享这些非静态方法
    3. 执行类中的静态代码块:如果有的话,对Person.class类进行初始化。
    4. 开辟空间:在堆内存中开辟空间,分配内存地址。
    5. 默认初始化:在堆内存中建立对象的特有属性,并进行默认初始化。
    6. 显式初始化:对属性进行显示初始化。
    7. 构造代码块:执行类中的构造代码块,对对象进行构造代码块初始化。
    8. 构造函数初始化:对对象进行对应的构造函数初始化。
    9. 将内存地址赋值给栈内存中的变量p。

    p.setName(“Feng”);

    1. 在栈内存中开辟setName()方法的空间,里面有:对象的引用this,临时变量name
    2. 将p的值赋值给this,this就指向了堆中调用该方法的对象
    3. 将"Feng"赋值给临时变量name
    4. 将临时变量的值赋值给this指向的name

    Person.showCountry();

    1. 在栈内存中,开辟showCountry()方法的空间,里面有:类名的引用Person
    2. Person指向方法区中的Person类的静态方法区的地址
    3. 调用静态方法区中的country,并输出
      • 注意:
      • 要想使用类中的成员,必须调用
      • 通过什么调用?
      • 类名,this,super。

    静态代码块、构造代码块和构造函数的区别

    静态代码块:用于给类初始化,类加载时就会被加载执行,只执行一次。

    构造代码块:用于给对象初始化,只要建立对象该部分都会执行,优先于构造函数执行,每个对象只执行一次。

    构造函数:给对象的对象初始化,建立对象是,选择相应的构造函数初始化对象

    创建对象时,三者被加载执行顺序是:静态代码块--->构造代码块--->构造函数

       1: class Person 
       2: {
       3:     //非静态变量,对象建立时存在于堆中
       4:     private int age = 0;
       5:     //静态变量,类加载时存在于方法区的静态部分
       6:     private static String country = "cn";
       7:     //静态代码块,类加载时,存在于方法区的静态部分
       8:     static
       9:     {
      10:         System.out.println("class load");
      11:     }
      12:     //构造代码块,类加载时,存在于方法区的静态部分
      13:     {
      14:         System.out.println("object load");
      15:     }
      16:  
      17:     Person(int age)
      18:     {
      19:         this.age = age;
      20:     }
      21:  
      22:     //静态方法,类加载时存在于方法区的静态部分
      23:     public static void showCountry()
      24:     {
      25:         System.out.println(country);
      26:     }
      27:     //非静态方法,类加载时存在于方法区的非静态部分
      28:     void print()
      29:     {
      30:         System.out.println(age);
      31:     }
      32: }

    总结

    类加载

    下列被加载:

    • 类变量(静态成员变量)
    • 静态和非静态方法
    • 静态代码块和构造代码块

    下列被执行:

    • 类变量的默认初始化和显式初始化
    • 静态代码块

    对象加载

    下列被加载:

    • 如果类第一次被用到,则先加载上面类的相关内容
    • 非静态成员变量

    下列被执行:

    • 非静态成员变量的默认初始化和显式初始化
    • 如果类第一次被用到,则先执行上面类的相关内容
    • 构造代码块
    • 构造函数

    存储位置

    memory

  • 相关阅读:
    BZOJ 1066 [SCOI2007]蜥蜴 (最大流)
    Codeforces 1092 D2 Great Vova Wall (Version 2) (栈)
    BZOJ 1046 [HAOI2007]上升序列(LIS + 贪心)
    牛客练习赛34 D little w and Exchange(归纳)
    BZOJ 1042 [HAOI2008]硬币购物(完全背包+容斥)
    GTMD并查集!
    2018icpc南京现场赛-G Pyramid(打标找规律+逆元)
    drwxr-xr-x 2 root root 4096 06-29 14:30 Test 分段解释
    Linux里面非常重要的目录
    点击 触发 事件 的 jQuery 写法样式
  • 原文地址:https://www.cnblogs.com/ShawnWithSmallEyes/p/3374235.html
Copyright © 2020-2023  润新知