Java虚拟机类加载的初始化
我们知道,《Java虚拟机规范》章节5.5 Initialization ^(1)^ 中严格规定了有且只有六种情况必须立即对类进行初始化:
遇到new(实例化对象)、getstatic(读取一个没有被final修饰、没有在编译期把结果放入常量池的类的静态字段)、putstatic(设置一个没有被final修饰、没有在编译期把结果放入常量池的类的静态字段)或者invokestatic(调用一个类的静态方法)这四条字节码指令时,如果类没有进行初始化则需要触发初始化。
使用java.lang.reflect包的方法对类型进行反射调用
父类还没有初始化
虚拟机启动时,用户需要制定一个要执行的主类(main)
当使用java7新加入的动态语言支持时,如果一个MthodHandle实例最后的解析结果是REF_getStatic、REF_putstatic、REF_invokestatic、REF_newInvokeSpecial四种类型的方法句柄
一个接口定义了default修饰的接口方法,同时接口的实现类发生了初始化
除此之外,所有引用类型的方式都不会触发初始化,称为被动引用:
子类引用 ...
匿名内部类形参为什么一定要final
最近在写一些匿名内部类的时候会感觉有些难以理解,所以重新复习了一下这部分内容。 发现了一些之前没注意到的点——匿名内部类的形参必须加final前缀(除非匿名内部类没使用它)
那么,怎么理解这个事情的背后原理呢?
内部类运作方式首先,思考内部类是怎么运行的。我们知道在内部类编译成功后,它会产生一个新的class文件。
该class文件仅仅只保留了对外部类的引用。
举个例子,当外部类传入的参数需要被内部类调用时,直接看起来好像就是被直接调用的:
12345678910111213public class OuterClass{ public void method(final String name,final int age){ class InnerClass{ public void show(){ System.out.println("your name is " + name + " and age is " + age); ...
构造器内部初始化实际过程
类初始化顺序类的初始化遵循的顺序很多人都知道是这样:(1)调用基类构造器,不断重复这个过程直到最底层(2)再按照声明的顺序调用成员的初始化方法(3)调用类构造器的主体
类初始化的实际过程但是,考虑这样一个例子:
12345678910111213141516171819202122232425262728293031class Animal{ public void walk(){ System.out.println("Animal.walk()"); } Animal(){ System.out.println("Animal() before walk()"); walk(); System.out.println("Animal() after walk()"); }}class Cat extends Animal{ private int step = 100; @Override public void walk() { ...