public class test { public static int a = 1; ... }
例如上面的代码,是先将 0
赋值给 a,而后在初始化的时候将 1
赋值给 a;java
将类的 .class 文件二进制数据读入到内存中,将其放置在运行时数据区的方法区内,而后在内存中建立一个java.lang.Class对象,用来封装类在方法区内的数据结构;
加载方式:数据库
System.exit()
方法;java.lang.invoke.MethodHandle
实例的解析结果REF_getStatic,REF_putStatic,REF_invokeStatic句柄对应的类没有初始化,则初始化;/** * 1. 对于静态字段来讲,只有直接定义了该字段的类才会被初始化 * 2. 当一个类初始化时,要求其父类已经所有初始化完成 * +XX:TraceClassLoading:用于追踪类的加载信息并打印出来 */ public class MyTest1 { public static void main(String[] args) { /** * MyParent1 static block * hello world */ System.out.println(MyChild1.str); /** * MyParent1 static block * MyChild1 static block * welcome */ // System.out.println(MyChild1.str2); } } class MyParent1 { public static String str = "hello world"; static { System.out.println("MyParent1 static block"); } } class MyChild1 extends MyParent1 { public static String str2 = "welcome"; static { System.out.println("MyChild1 static block"); } }
控制台输出信息网络
[Loaded com.godfunc.jvm.classloader.MyParent1 from file:/Users/godfunc/WorkSpace/IdeaSpace/learn-java/jvm/build/classes/java/main/] [Loaded com.godfunc.jvm.classloader.MyChild1 from file:/Users/godfunc/WorkSpace/IdeaSpace/learn-java/jvm/build/classes/java/main/] MyParent1 static block hello world
JVM规范容许类加载器在预料某个类将要被使用时就预先加载它,若是在预先加载中遇到了.class文件缺失或者存在错误,类加载器必须在程序“首次主动使用”该类时才报告错误(LinkageError错误),若是这个类一直没有被主动使用,那么类加载器就不会报告这个错误。数据结构
/** * 常量在编译阶段会被存入到调用这个常量的方法所在的类的常量池当中,本质上,调用类并无直接引用到定义常量的类, * 所以并不会触发定义常量的类的初始化 * 注意:这里的指的是将常量放到了MyTest2的常量池中,以后MyTest2和MyParent2就没有任何关系了 * 甚至能够删除MyParent2的class文件 * 助记符: * ldc表示将int, float, 或者String的常量值从常量池推送至栈顶。 * bipush表示将单字节(-128 ~ 127)的常量推送至至栈顶 * sipush表示将将一个整型(-32768 ~ 32767)常量值推送至栈顶 * iconst_1表示将int型的1推送至栈顶。-1到5 (iconst_m1 ~ iconst_5) */ public class MyTest2 { public static void main(String[] args) { System.out.println(MyParent2.str); } } class MyParent2 { public static final String str = "hello world"; static { System.out.println("MyParent2 static block"); } }
/** * 当一个常量的值并不是编译器能够肯定的,那么其值就不会被放到调用类的常量池中, * 这时程序运行时,会致使主动使用这个常量所在的类,显然会致使这个类被初始化。 */ public class MyTest3 { public static void main(String[] args) { /** * MyParent3 static block * 59ddfbea-ed41-4ab9-a945-88466d6a5ead */ System.out.println(MyParent3.str); } } class MyParent3 { public static final String str = UUID.randomUUID().toString(); static { System.out.println("MyParent3 static block"); } }
/** * 在准备阶段,counter1=0 counter=0,而后进入初始化阶段时counter1初始化为1,执行new Singleton(),counter1 + 1 = 2,counter2 + 1 = 1 * 而后初始化counter2,counter2的值被初始化为0,最后输出的结果为 2 0 */ public class MyTest6 { public static void main(String[] args) { Singleton signleton = Singleton.getSingleton(); // 2 1 System.out.println(Singleton.counter1 + " " + Singleton.counter2); } } class Singleton { public static int counter1 = 1; private static Singleton singleton = new Singleton(); private Singleton() { counter1 += 1; counter2 += 1; System.out.println(counter1); System.out.println(counter2); } public static int counter2 = 0; public static Singleton getSingleton() { return singleton; } }
/** * 当一个类被初始化的时候,它所实现的接口是不会被初始化的 */ public class MyTest5 { public static void main(String[] args) { // 6 System.out.println(MyChild5.b); } } interface MyParent5 { public static Thread thread = new Thread() { { System.out.println("MyParent5 invoked"); } }; } class MyChild5 implements MyParent5 { public static int b = 6; }
根类(启动类)加载器 -> 扩展类加载器 -> 系统类加载器 -> 用户自定义类加载器dom