类的加载机制

来源:互联网 发布:python中syntax error 编辑:程序博客网 时间:2024/05/18 00:42

1、同一个jvm的所有线程、变量都处于同一个进程里,他们都使用jvm进程的内存区。

jvm进程停止的情况:程序正常运行结束;遇到没有捕获的Exception 或者Error;程序遇到System.exit()或者Runtime.getRuntime.exit()  (遇到这两个方法 finally也不会执行);平台强制关闭jvm

例子: class A{   public static int i =6}  

public class T1{ public static void main(...){  A  a=new A();  a.i++;   System.out.println(a.i)}

public class T2{ public static void main(...){  A b=new A();  Sys...println(b.i) ;}}

问两次输出结果是什么?  答案:7和6,因为T1  T2是两次运行jvm进程的,他们不会共享数据的,第一次jvm结束后,它将A作出的修改都剔除

2. 类加载

(1)Java中类的加载、连接、初始化都是在运行期完成的,虽然加载过程耗时,但增加了Java的灵活性,动态加载、动态连接

(2)类的生存周期:加载、连接(验证  准备  解析)初始化  使用 卸载。

(3)各个阶段开始的顺序基本固定,除了解析,多数时候解析实在初始化前开始的,但是解析也可以在初始化开始之后开始,即运行时绑定(泛化)

(4)


3.初始化的5种情况(有且只有 主动引用)

(1)new  或者get put  一个static变量 或者调用静态方法时

(2)使用Java.lang.reflect包对类进行反射调用时,如果类没有初始化要先初始化

(3)子类要初始化,它父类还没有初始化的时候,要先初始化父类

(4)jvm启动的时候,要先初始化主类(包含main方法的那个类)

(5)jdk1.7  java.lang.invoke.MethodHandle实例最后的解析结果REF_getstatic/REF_putstatic/REF_invokestatic的方法句柄,并且这个方法句柄对应的类没有初始化,那么那个类要先初始化。

(MethodHandle方法句柄类,有点类似于反射中的Method类 具体见)


被动引用:除了上述5种外都是不会触发初始化的

4.重点例子(被动引用)

(1)通过子类引用父类的静态变量,不会导致子类初始化,对于静态变量,只有直接定义这个变量的类才会被初始化

class SuperClass{static {System.out.println("superclass init");}public static int i=123;}class SubClass extends SuperClass{static{System.out.println("subclass init");}}public class Run {public  static void main(String[] args){System.out.println(SubClass.i);}}

superclass init123
(2)通过数组定义引用类,不会触发此类的初始化,这里是定义
public class Run {public  static void main(String[] args){SubClass[] subClasses=new  SubClass[10];}}
(3)常量在编译阶段存入类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发类的初始化

class SuperClass{static {System.out.println("superclass init");}public static final int i=123;}public class Run {public  static void main(String[] args){System.out.println(SuperClass.i);}}

结果只输出123,在编译阶段将123存入到Run类的常量池中了,注意是Run类的常量池中, 所以在调用SuperClass.i时,其实是在Run类的常量池中取出的,


5、接口的初始化过程

接口中不允许有static块,但编译器仍然为接口生成<clinit>类构造器,用于初始化接口中的成员变量。

当一个接口初始化时和类不同,接口在初始化时并不要求父亲接口初始化,只有在用到哪个父接口时才初始化,而类在初始化之前要初始化它的全部父类。

1 0
原创粉丝点击