前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JAVA JVM类加载过程的学习

JAVA JVM类加载过程的学习

原创
作者头像
逆回十六夜
修改2019-09-12 12:32:17
4600
修改2019-09-12 12:32:17
举报
文章被收录于专栏:逆回十六夜

学习资料链接:https://www.bilibili.com/video/av30023103/

链接 将JAVA类的二进制代码合并到JVM的运行状态之中的过程

1.验证:

确保加载的类信息符合JVM的规范,没有安全方面的问题。

2.准备:

正式为类变量(static变量)分配内存并设置类变量初始值的阶段(该初始值只是默认的初始值,并不是代码中设定的值)这些内存都将在方法区进行分配。

3.解析:

虚拟机常量池内的符号引用替换为直接引用的过程。

初始化

  • 1.初始化阶段实质性类构造器<clinit>()方法的过程。类构造器<clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static块)中的语句合并产生的。
  • 2.当初始化一个类的时候,如果发现其父类还没有进行过初始化.则需要先进行其父类的初始化。
  • 3.虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步。

类加载全过程

1.类的主动引用(一定会发生类的初始化)

  • new一个类的对象
  • 调用类的静态成员(除了final常量)和静态方法
  • 使用java.lang.reflect包的方法对类进行反射调用
  • 当虚拟机启动,java XXX,则一定会初始化XXX类,说白了就是先启动main方法所在的类
  • 当初始化一个类,如果其父类没有被初始化,则先会初始化他的父类

2.类的被动引用(不会发生类的初始化)

  • 当访问一个静态域时,只有真正声明这个域的类才会被初始化
  • 通过子类引用父类的静态变量,不会导致子类初始化
  • 通过数组定义类引用,不会触发此类的初始化
  • 引用常量不会触发此类的初始化(常量在编译阶段就存入调用类的常量池中了)


实验代码:

代码语言:javascript
复制
package classinit;

public class Demo01 {
    static{
        System.out.println("Demo01静态块初始化");
    }
    public static void main(String[] args){
        System.out.println("Demo01的main方法执行");
        new A();
    }
}

class A extends A_Father{
    public static int width = 100;

    static{
        System.out.println("静态初始化类A");
        width = 300;
    }
}

class A_Father{
    static{
        System.out.println("静态初始化A的父类");
    }
}

实验结果:


实验代码:

代码语言:javascript
复制
public static void main(String[] args){
    System.out.println("Demo01的main方法执行");
    System.out.println(A.width);
}

实验结果:

同样也初始化了
同样也初始化了

实验代码:

代码语言:javascript
复制
package classinit;

public class Demo01 {
    static{
        System.out.println("Demo01静态块初始化");
    }
    public static void main(String[] args){
        System.out.println("Demo01的main方法执行");
        System.out.println(A.MAX);
    }
}

class A extends A_Father{
    public static int width = 100;
    public static final int MAX = 200;
    static{
        System.out.println("静态初始化类A");
        width = 300;
    }
}

class A_Father{
    static{
        System.out.println("静态初始化A的父类");
    }
}

实验结果:

final并不会进行类的初始化
final并不会进行类的初始化

实验代码:

代码语言:javascript
复制
package classinit;

public class Demo01 {
    static{
        System.out.println("Demo01静态块初始化");
    }
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println("Demo01的main方法执行");
        //主动引用
        //new A();
        //System.out.println(A.width);
        Class.forName("classinit.A");
        //被动引用
        //System.out.println(A.MAX);
    }
}

class A extends A_Father{
    public static int width = 100;
    public static final int MAX = 200;
    static{
        System.out.println("静态初始化类A");
        width = 300;
    }
}

class A_Father{
    static{
        System.out.println("静态初始化A的父类");
    }
}

实验结果:

通过反射也可以主动引用实现初始化
通过反射也可以主动引用实现初始化

实验代码:

代码语言:javascript
复制
public static void main(String[] args) throws ClassNotFoundException {
    System.out.println("Demo01的main方法执行");
    //主动引用
    //new A();
    //System.out.println(A.width);
    //Class.forName("classinit.A");
    //被动引用
    //System.out.println(A.MAX);
    A[] as = new A[10];
}

实验结果:

声明数组不会初始化类
声明数组不会初始化类

实验代码:

代码语言:javascript
复制
public static void main(String[] args) throws ClassNotFoundException {
    System.out.println("Demo01的main方法执行");
    //主动引用
    //new A();
    //System.out.println(A.width);
    //Class.forName("classinit.A");
    //被动引用
    //System.out.println(A.MAX);
    A[] as = new A[10];
}

实验结果:

声明数组不会初始化类


实验代码:

代码语言:javascript
复制
package classinit;

public class Demo01 {
    static{
        System.out.println("Demo01静态块初始化");
    }
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println("Demo01的main方法执行");
        //主动引用
        //new A();
        //System.out.println(A.width);
        //Class.forName("classinit.A");
        //被动引用
        //System.out.println(A.MAX);
        //A[] as = new A[10];
        System.out.println(B.width);
    }
}

class A extends A_Father{
    public static int width = 100;
    public static final int MAX = 200;
    static{
        System.out.println("静态初始化类A");
        width = 300;
    }
}

class A_Father{
    static{
        System.out.println("静态初始化A的父类");
    }
}

class B extends A{
    //public static int width = 100;
    static{
        System.out.println("静态初始化类B");
    }
}

实验结果:

子类B并没有初始化,其静态变量的调用本质上是调用其父类,然而若是B也有该同名的静态变量,父类的静态变量变为redundant(多余的)
子类B并没有初始化,其静态变量的调用本质上是调用其父类,然而若是B也有该同名的静态变量,父类的静态变量变为redundant(多余的)

补充:JAVA内存分析详解--笔记

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 链接 将JAVA类的二进制代码合并到JVM的运行状态之中的过程
    • 1.验证:
      • 2.准备:
        • 3.解析:
        • 初始化
          • 1.类的主动引用(一定会发生类的初始化)
            • 2.类的被动引用(不会发生类的初始化)
              • 实验代码:
              • 实验结果:
              • 实验代码:
              • 实验结果:
              • 实验代码:
              • 实验结果:
              • 实验代码:
              • 实验结果:
              • 实验代码:
              • 实验结果:
              • 实验代码:
              • 实验结果:
              • 实验代码:
              • 实验结果:
          • 补充:JAVA内存分析详解--笔记
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档