A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 冯纪纲 于 2012-11-12 16:18 编辑

今天去涉猎了一下类的加载的过程,现在总结如下:
一个java文件从被加载到被卸载这个生命周期,总共要经历5个阶段:
加载->链接(验证+准备+解析)->初始化(使用前的准备)->使用->卸载
其中加载(除了自定义加载)+链接的过程是完全由jvm负责的,什么时候要对类进行初始化工作(加载+链接在此之前已经完成了),jvm有严格的规定(五种情况):
1.遇到new,getstatic,putstatic,invokestatic这4条字节码指令时,假如类还没进行初始化,则马上对其进行初始化工作。其实就是3种情况:用new实例化一个类时、读取或者设置类的静态字段时(不包括被final修饰的静态字段,因为他们已经被塞进常量池了)、以及执行静态方法的时候。
2.使用java.lang.reflect.*的方法对类进行反射调用的时候,如果类还没有进行过初始化,马上对其进行。
3.初始化一个类的时候,如果他的父亲还没有被初始化,则先去初始化其父亲。
4.当jvm启动时,用户需要指定一个要执行的主类(包含static void main(String[] args)的那个类),则jvm会先去初始化这个类。
5.用Class.forName(String className);来加载类的时候,也会执行初始化动作。注意:ClassLoader的loadClass(String className);方法只会加载并编译某类,并不会对其执行初始化。
以上5种预处理称为对一个类进行主动的引用,其余的其他情况,称为被动引用,都不会触发类的初始化。下面也举了些被动引用的例子:
  1. /**
  2. * 被动引用情景1
  3. * 通过子类引用父类的静态字段,不会导致子类的初始化
  4. * @author gang
  5. *
  6. */
  7. class SuperClass{
  8.         static{
  9.                 System.out.println("super class init.");
  10.         }
  11.         public static int value=123;
  12. }

  13. class SubClass extends SuperClass{
  14.         static{
  15.                 System.out.println("sub class init.");
  16.         }
  17. }

  18. public class test{
  19.         public static void main(String[]args){
  20.                 System.out.println(SubClass.value);
  21.         }
  22.         
  23. }
复制代码
  1. /**
  2. * 被动引用情景2
  3. * 通过数组引用来引用类,不会触发此类的初始化
  4. * @author gang
  5. *
  6. */
  7. public class test{
  8.         public static void main(String[] args){
  9.                 SuperClass s_list=new SuperClass[10];
  10.         }
  11. }
复制代码
  1. /**
  2. * 被动引用情景3
  3. * 常量在编译阶段会被存入调用类的常量池中,本质上并没有引用到定义常量类类,所以自然不会触发定义常量的类的初始化
  4. * @author gang
  5. *
  6. */
  7. class ConstClass{
  8.         static{
  9.                 System.out.println("ConstClass init.");
  10.         }
  11.         public final static String value="hello";
  12. }

  13. public class test{
  14.         public static void main(String[] args){
  15.                 System.out.println(ConstClass.value);
  16.         }
  17. }
  18. 输出结果:hello
复制代码
以上是针对类的初始化,接口也要初始化,接口的"类似"初始化跟类的初始化有什么区别呢?求教诸大神

评分

参与人数 1技术分 +1 收起 理由
滔哥 + 1

查看全部评分

2 个回复

倒序浏览
接口是不能初始化的,定义的接口对象使用其子类进行实例化

评分

参与人数 1技术分 +1 收起 理由
滔哥 + 1

查看全部评分

回复 使用道具 举报
给出代码都是用static{}来输出初始化信息的,接口当然没法做到,但接口初始化的时候编译器仍然会给接口生成一个类构造器,用来初始化接口中的成员变量,这点在类的初始化上也有做到。真正不同的地方在于第三点,类的初始化执行之前要求父类全部都初始化完成了,但接口的初始化却有些不同,也就是说,子接口初始化的时候并不要求其父接口也完成初始化,只有在真正使用到父接口的时候它才会被初始化,比如引用接口上的常量的时候

评分

参与人数 1技术分 +1 收起 理由
滔哥 + 1

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马