类的主动引用
笔试题1:
public class Test1 {
static{
System.out.println("Test1 static");
}
}
public class Main {
public static void main(String[] args) {
Test1 t=new Test1();
}
}
结果:
Test1 static
主动引用定义1:new一个对象的时候会发生类初始化,调用
笔试题2:
public class Test2 {
static final int count = 1;
static{
System.out.println("Test2 static");
}
}
public class Main {
public static void main(String[] args) {
int n=Test2.count;
}
}
结果:
什么都没有
主动引用定义2:调用类中的静态成员,除了final字段,final被调用但是没有初始化类。
没有任何输出,就是因为那个final字段,Java编译器把这样的字段解析成对常量的本地拷贝。
常量是一种特殊的变量,因为编译器把他们当做值(value)而不是域(field)来对待。
如果你的代码中用到了常变量(constant variable),编译器并不会生成字节码来从对象中载入域的值,而是直接把这个值插入到字节码中。
这是一种很有用的优化,但是如果你需要改变final域的值,那么每一块用到的那个与的代码都需要重新编译。
笔试题3:
public class Test3 {
static void Output(){
System.out.println("Output !");
}
static{
System.out.println("Test3 static");
}
}
public class Main {
public static void main(String[] args) {
Test3.Output();
}
}
输出的结果
Test3 static
Output !
主动引用定义3:调用某个类的静态方法,那么这个类一定先初始化。
笔试题4:
public class Test4 {
static final int count = 1;
static{
System.out.println("Test4 static");
}
}
public class Main {
public static void main(String[] args) {
try {
Class aClass = Class.forName("com.oyb.jvm.test01.lesson05.Test4");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
输出的结果:
Test4 static
主动引用定义4:反射调用,触发类初始化
使用java.lang.reflect包方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
通过调用java.lang.Class.forName(String className)
笔试题5:
public class Father {
static{
System.out.println("Initialize class father");
}
}
public class Son extends Father{
static{
System.out.println("Initialize class son");
}
}
public class Main {
public static void main(String[] args) {
Son son=new Son();
}
}
输出结果:
Initialize class father
Initialize class son
类的主动引用定义5:先初始化父类。再初始化子类。
当初始化一个类的时候,如果发现父类没有进行初始化,则需要先触发其父类的初始化
笔试题6:
public class Test6 {
static {
System.out.println("static init ...");
}
public static void main(String[] args) {
System.out.println("main begin ...");
}
}
输出结果:
static init …
main begin …
类的主动引用定义6:当虚拟机启动时,用户需要制定一个执行的主类,虚拟机会首先初始化这个主类。
主动引用总结:
对类(B类)进行引用时,如果类没有进行过初始化,则先触发其初始化叫做主动引用。
主动引用6中定义:
主动引用定义1:new一个对象的时候会发生类初始化,调用
主动引用定义2:调用类中的静态成员,除了final字段,final被调用但是没有初始化类。
主动引用定义3:调用某个类的静态方法,那么这个类一定先初始化。
主动引用定义4:反射调用,触发类初始化。
主动引用定义5:先初始化父类。再初始化子类。
主动引用定义6:当虚拟机启动时,用户需要制定一个执行的主类,虚拟机会首先初始化这个主类。
类的被动引用
笔试题1:
public class Father {
static int count = 1;
static{
System.out.println("Initialize class father");
}
}
public class Son extends Father {
static{
System.out.println("Initialize class son");
}
}
public class Main {
public static void main(String[] args) {
int n = Son.count;
}
}
执行的结果:
Initialize class father
被动引用定义1:通过子类引用父类的静态变量,不会导致子类初始化。
虽然是以Son.count形式调用的,但是因为count是Father的静态成员变量,所以只初始化Father类,而不初始化Son类。
笔试题2:
public class Test1 {
static{
System.out.println("Initialize class Test1");
}
}
public class Main {
public static void main(String[] args) {
Test1[] e = new Test1[10];
}
}
执行的结果:
没有任何输出
被动引用定义2:通过数组定义类引用类,不会触发类的初始化。
笔试题3:
public class Test2 {
static final int count = 1;
static{
System.out.println("Initialize class Test2");
}
}
public class Main {
public static void main(String[] args) {
int n = Test2.count;
}
}
执行结果:
没有任何输出
被动引用定义3:不会触发定义常量的类的初始化。
常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。
Test2类中定义的count是final对象,其在编译阶段就会存入调用类的常量池中。
被动引用总结
除了主动引用外,所有引用类的方式都不会触发初始化,称为被动引用。
被动引用定义1:通过子类引用父类的静态变量,不会导致子类初始化。
被动引用定义2:通过数组定义类引用类,不会触发类的初始化。
被动引用定义3:不会触发定义常量的类的初始化