分析:
说明:
内存中存在栈、堆(放创建好的对象)、方法区(实际也是一种特殊堆)
1、JVM加载Demo01时候,首先在方法区中形成Demo01类对应静态数据(类变量、类方法、代码…),同时在堆里面也会形成java.lang.Class对象(反射对象),代表Demo01类,通过对象可以访问到类二进制结构。然后加载变量A类信息,同时也会在堆里面形成a对象,代表A类。
2、main方法执行时会在栈里面形成main方法栈帧,一个方法对应一个栈帧。如果main方法调用了别的方法,会在栈里面挨个往里压,main方法里面有个局部变量A类型的a,一开始a值为null,通过new调用类A的构造器,栈里面生成A()方法同时堆里面生成A对象,然后把A对象地址付给栈中的a,此时a拥有A对象地址。
3、当调用A.width时,调用方法区数据。
当类被引用的加载,类只会加载一次
类的主动引用(一定会发生类的初始化)
①new一个类的对象
②调用类的静态成员(除了final常量)和静态方法
③使用java.lang.reflect包的方法对类进行反射调用
④当虚拟机启动,java Demo01,则一定会初始化Demo01类,说白了就是先启动main方法所在的类
⑤当初始化一个类,如果其父类没有被初始化,则先初始化它父类
类的被动引用(不会发生类的初始化)
①当访问一个静态域时,只有真正声名这个域的类才会被初始化
②通过子类引用父类的静态变量,不会导致子类初始化
③通过数组定义类的引用,不会触发此类初始化
④引用常量不会触发此类的初始化(常量在编译阶段就存入调用类的常量池中了)
1 public class Demo01 { 2 static{ 3 System.out.println("静态初始化demo01"); 4 } 5 6 public static void main(String[] args) { 7 System.out.println("静态初始化demo01.main"); 8 /*String str = "aaa"; 9 int a = 23435;*/ 10 //调用A类的方法 11 A a = new A(); 12 13 //通过反射调用 14 /* try { 15 Class.forName("com.zzp.A"); 16 } catch (ClassNotFoundException e) { 17 e.printStackTrace(); 18 }*/ 19 20 //注意打印出来的width的值和程序执行的顺序 21 //主动引用 22 // System.out.println(a.width); 23 24 //被动引用 25 // System.out.println(a.b); 26 27 //数组初始化 28 //A[] as = new A[10]; 29 30 System.out.println(B.width); 31 } 32 } 33 34 //创建一个B类,继承A 35 class B extends A{ 36 static{ 37 System.out.println("静态初始化B"); 38 } 39 } 40 41 42 class A extends A_Father{ 43 public static int width = 100; 44 public static final int b= 100; 45 static{ 46 System.out.println("静态初始化A"); 47 width = 300; 48 } 49 public A(){ 50 System.out.println("创建A类的对象"); 51 } 52 } 53 54 class A_Father{ 55 static{ 56 System.out.println("静态初始化A_Father"); 57 } 58 }