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文件加载时,静态方法和非静态方法都会被加载到方法区中,只不过要调用非静态方法时需要先实例化一个对象,对象才能调用非静态方法。如果让类中所有的非静态方法都随着对象的实例化而建立一次,那么会大量消耗内存资源,所以才会让所有对象共享这些非静态方法
  • 执行类中的静态代码块:如果有的话,对Person.class类进行初始化。
  • 开辟空间:在堆内存中开辟空间,分配内存地址。
  • 默认初始化:在堆内存中建立对象的特有属性,并进行默认初始化。
  • 显式初始化:对属性进行显示初始化。
  • 构造代码块:执行类中的构造代码块,对对象进行构造代码块初始化。
  • 构造函数初始化:对对象进行对应的构造函数初始化。
  • 将内存地址赋值给栈内存中的变量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: }

    总结

    类加载

    下列被加载:

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

    下列被执行:

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

    对象加载

    下列被加载:

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

    下列被执行:

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

    存储位置

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

    上一篇:如何使用Scrapy框架实现网络爬虫


    下一篇:NDK JNI 的关键点