论坛首页 Java企业应用论坛

Class loading之惑

浏览 4089 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-01-25  
    最近遇到一件怪事,打破了我多年来对java dynamic class loading习惯性的粗浅的认识……
    问题是这样,假设有一个class A,在它的某个方法test()中引用了class B, 如果A在运行的过程没有执行到test(),根据load class on demand的原理,B就不会没load。
代码如下:
java 代码
 
  1. public class A {  
  2.     public static void main(String[] args) {  
  3.         A a = new A();  
  4.         a.print(); 
  5.     }  
  6.      
  7.     public void print() {  
  8.         System.out.println("hello class loading");  
  9.     }  
  10.      
  11.     public void test(){  
  12.         B b = new B();  
  13.         b.smile();  
  14.     }  
  15.     
  16. }  
  17.   
  18. public class B {  
  19.     public void smile() {  
  20.         System.out.println(";-)");  
  21.     }  
  22. }  
   
    打开verbose选项可以看到B并不会被load,符合我们的习惯性认识。但是如果现在加入一个interface C,在test()方法中创建一个C的实例,并调用该实例的某个方法,就可以看到即使test()方法没有执行,C依然会被load到虚拟机中!
java 代码
 
  1. public class A {  
  2.     public static void main(String[] args) {  
  3.         A a = new A();  
  4.         a.print();  
  5.     }  
  6.       
  7.     public void print() {  
  8.         System.out.println("hello class loading");  
  9.     }  
  10.       
  11.     public void test(){  
  12.         B b = new B();  
  13.         b.smile();  
  14.         C c = new C() {  
  15.             public void cry() {  
  16.                 System.out.println("cry...");  
  17.             }  
  18.         };  
  19.         c.cry();  
  20.     }  
  21. }  
  22. public interface C {  
  23.     public void cry();  
  24. }  
   
摘一段执行的log:
……
[Loaded java.security.cert.Certificate from C:\jdk150_04_for_netbeans\jre\lib\rt.jar]
[Loaded A from file:/D:/eclipse-SDK-3.2-win32/workspace/cl/]
[Loaded C from file:/D:/eclipse-SDK-3.2-win32/workspace/cl/]
hello class loading
[Loaded java.lang.Shutdown from C:\jdk150_04_for_netbeans\jre\lib\rt.jar]
[Loaded java.lang.Shutdown$Lock from C:\jdk150_04_for_netbeans\jre\lib\rt.jar]

    如果不用匿名类,而使用一个具体的C的实现CImpl,情况会略有不同:如果引用的是interface,即C c= new CImpl(); C依然会被load进来,如果引用是实现类,即CImpl c = new CImpl(); 则C和CImpl都不会被load。

    查了language spec也没有找到理论依据,那位给解释解释这是什么原因造成的?
   发表时间:2007-01-25  
应该是虚拟机进行字节码验证的时候对类型进行检查引起的。

如果用接口C引用CImpl,classloader应该会载入C和CImpl来检查C是否能够引用CImpl。

如果是用CImpl引用CImpl的话,就不需要载入来进行验证了。

这个是我推测的,不一定正确。
0 请登录后投票
   发表时间:2007-01-26  
foxty 写道
应该是虚拟机进行字节码验证的时候对类型进行检查引起的。

如果用接口C引用CImpl,classloader应该会载入C和CImpl来检查C是否能够引用CImpl。

如果是用CImpl引用CImpl的话,就不需要载入来进行验证了。

这个是我推测的,不一定正确。
谢谢,但是我的问题是:为什么方法test()并没有被执行,接口C却被载入了呢?因为即使我使用匿名类,接口C依然会被载入进来。
0 请登录后投票
   发表时间:2007-01-26  
内部匿名类随类装载而装载,由于内部匿名类是继承法了接口C, 在装载过程中必须认识"C"才能装匿名类.
0 请登录后投票
   发表时间:2007-01-26  
都是高手
0 请登录后投票
   发表时间:2007-01-27  
it's tricky, should avoid?
0 请登录后投票
   发表时间:2007-01-28  
terrine 写道
foxty 写道
应该是虚拟机进行字节码验证的时候对类型进行检查引起的。

如果用接口C引用CImpl,classloader应该会载入C和CImpl来检查C是否能够引用CImpl。

如果是用CImpl引用CImpl的话,就不需要载入来进行验证了。

这个是我推测的,不一定正确。
谢谢,但是我的问题是:为什么方法test()并没有被执行,接口C却被载入了呢?因为即使我使用匿名类,接口C依然会被载入进来。


虚拟机进行字节码验证的时候会对整个类的字节码进行验证,所以这里跟你执行不执行没有关系。
0 请登录后投票
   发表时间:2007-01-28  
foxty,假设这里只有一句
C c = new CImpl();
并不使用变量c(c作为参数或者调用c的方法),可以看到C和CImpl都不会被装载进来。你所说的对字节码进行验证指的是什么呢?按照你之前的说法,这里依然用接口C引用了CImpl,C和CImpl就应该也被装载进来才对。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics