在以下几种状况下,java虚拟机将结束生命周期java
类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区,而后在
堆区建立一个java.lang.Class对象,用来封装类在方法区内的数据结构程序员
类的加载的最终产品是位于堆区中的Class对象
Class对象封装了类在方法区内的数据结构,而且向java程序员提供了访问方法区内的数据结构的接口数据库
有两种类型的类加载器安全
public class ClassLoaderDemo { public static void main(String[] args) { ClassLoader loader = ClassLoaderDemo.class.getClassLoader(); while(loader!=null){ System.out.println(loader.getClass().getName()); loader = loader.getParent(); } System.out.println(String.class.getClassLoader()); } }
类被加载后,就进入链接阶段,链接就是将已经读入到内存的类的二进制数据合并到虚拟机的运行时环境中去
类的验证内容网络
在准备阶段,java虚拟机为类的静态变量分配内存,并设置默认的初始值,例如对于Sample类,在准备阶段,将int类型的静态变量a分配4个字节的内存
空间,而且赋予默认值0,为long类型的静态变量b分配8个字节的内存空间,而且赋予默认值0数据结构
在解析阶段,java虚拟机会把类的二进制数据中的符号引用替换为直接引用,例如在Worker类的gotoWork()方法中会引用Car类的run()方法
public void gotoWorker(){ car.run(); }
在Worker类的二进制数据中,包含了一个对Car类的run()方法的符号引用,它由run()方法的全名和相关描述符组成,在解析阶段,java虚拟机会把
这个符号引用替换为一个指针,该指针指向Car类的run()方法在方法区内的内存位置,这个指针就是直接引用dom
在初始化阶段,java虚拟机执行类的初始化语句,为类的静态变量赋予初始值,在程序中,静态变量的初始化有两种途径:jvm
public class Sample{ private static int a = 1; // 在静态变量的声明处进行初始化 public static long b; public static long c; static{ b = 2; } // 在静态代码块中进行初始化 }
class Singleton { //private static Singleton singleton = new Singleton(); // counter1=1 counter2=0 public static int counter1; public static int counter2 = 0; private static Singleton singleton = new Singleton(); // counter1=1 counter2=1 private Singleton(){counter1++; counter2++;} public static Singleton getInstance(){return singleton;} } public class MyTest{ public static void main(String[] args) { Singleton singleton = Singleton.getInstance(); System.out.println("counter1= " + singleton.counter1); System.out.println("counter2= " + singleton.counter2); } }
静态变量的声明语句,以及静态代码块都被看作类的初始化语句,java虚拟机会按照初始化语句在类文件中的前后顺序来依次执行它们
例如当如下Sample类被初始化后它的静态变量a的取值为4操作系统
public class Sample{ static int a = 1; static{ a = 2; } static{ a = 4; } public static void main(String[] args){ System.out.println("a= " + a)} // 打印a=4 }
class FinalTest{ public static final int x = 6/3; // 编译时肯定 不会致使类初始化 // public static final int x = new Random().nextInt(100); // 运行时变量 对类进行初始化 static{ System.out.println("FinalTest static block"); } } public class Test2 { public static void main(String[] args) { System.out.println(FinalTest.x); } }
当java虚拟机初始化一个类时,要求它的全部父类都已经被初始化,可是这条规则并不适用于接口
在初始化一个类时,并不会先初始化它所实现的接口
在初始化一个接口时,并不会先初始化它的父接口
所以,一个父接口并不会由于它的子接口或者实现类的初始化而初始化,只有当程序首次使用特定接口的静态变量时才会致使接口初始化指针
public class Test3 { static{ System.out.println("Test3 static block"); } public static void main(String[] args) { System.out.println(Child.b); } } class Parent{ static int a = 3; static{ System.out.println("Parent static block"); } } class Child extends Parent{ static int b = 4; static{ System.out.println("Child static block"); } }
输出:
Test3 static block
Parent static block
Child static block
4
public class Test4 { static{ System.out.println("Test4 static block"); } public static void main(String[] args) { Parent parent; System.out.println(Parent2.a); System.out.println(Child2.b); } } class Parent2{ static int a = 3; static{ System.out.println("Parent2 static block"); } } class Child2 extends Parent2{ static int b = 4; static{ System.out.println("Child2 static block"); } }
输出:
Test4 static block
Parent2 static block
3
Child2 static block
4
对子类的主动使用会致使父类被初始化,但对父类的主动使用并不会致使子类初始化(不可能说生成一个Object类的对象致使全部子类初始化)
只有当程序访问的静态变量或静态方法确实在当前类或当前接口中定义时,才能够认为是对类或接口的主动使用
public class Test5 { public static void main(String[] args) { System.out.println(Child3.a); Child3.doSomething(); } } class Parent3{ static int a = 3; static{ System.out.println("Parent3 static block"); } static void doSomething(){ System.out.println("do something"); } } class Child3 extends Parent3{ static{ System.out.println("Child3 static block"); } }
输出:
Parent3 static block
3
do something
调用ClassLoader类的loadClass方法加载一个类,并非对类的主动使用,不会致使类的初始化
public class Test6 { public static void main(String[] args) throws Exception{ ClassLoader loader = ClassLoader.getSystemClassLoader(); loader.loadClass("com.ak.cls.C"); System.out.println("line"); Class.forName("com.ak.cls.C"); } } class C{ static{ System.out.println("Class C"); } }
输出: line Class C