DANCE WITH JAVA

开发出高质量的系统

常用链接

统计

积分与排名

好友之家

最新评论

一个有趣的现象

   无意间发现了一个有趣的现象。下边是重现整个现象的过程。
1,编写一个接口
package iface;
public interface MyInt {

}

把这个接口做成一个jar包iface.jar
2,编写一个类
package mylib;

import iface.MyInt;

public class MyJar {
    
public static boolean isMyInterface(){
        
return null==getMyInt();
    }

    
public static MyInt getMyInt(){
        
return null;
    }

}

同样把这个类做成一个jar文件mylib.jar
3,新建一个工程,加入两个jar包。然后写一个测试类
import mylib.MyJar;

public class Test {
    
public static void main(String[] args) {
        System.out.println(MyJar.isMyInterface());
        System.out.println(MyJar.getMyInt());
    }

}

4,运行得到结果:
true
null
到这里一切正常,下边开始不同的地方。
5,把iface.jar从工程中移走,这时测试类出现编译错误,这是因为MyJar.getMyInt()要返回一个MyInt类型的对象,而MyInt接口不存在。
删掉测试类的第二个println 变成这样
import mylib.MyJar;

public class Test {
    
public static void main(String[] args) {
        System.out.println(MyJar.isMyInterface());
    }

}

重新编译,通过。运行得到结果 :
true
8,分析:移走接口后导致测试类第二行println()中的代码Myjar.getMyInt()编译不过去,不能之行,是因为找不到MyInt接口
但第一行能编译,且能执行,而第一行的代码在内部其实是调用第二行的,但依然能执行成功。
这就说同样的函数:MyJar.getMyInt()外部调用不能执行,通过一个函数转一下就能执行,呵呵,挺有趣。
感觉应该是虚拟机的实现机制方面的原因。详细情形还没有确认。

posted on 2007-07-05 01:00 dreamstone 阅读(1759) 评论(14)  编辑  收藏 所属分类: jdk相关

评论

# re: 一个有趣的现象[未登录] 2007-07-05 09:15 刘明

估计可能在null==getMyInt();这里的时候,getMyInt()不存在,直接为null吧?大概,需要测试一下。  回复  更多评论   

# re: 一个有趣的现象 2007-07-05 09:38 dennis

没必要打包成jar都有这个现象,将MyInt.class删除也一样。
MyInt从来没有被连接过(link),仅仅是被尝试装载(load),而装载MyInt类但是没有使用是不会抛出NoClassDefFoundError的。  回复  更多评论   

# re: 一个有趣的现象[未登录] 2007-07-05 09:45 刘明

将iface.jar移走后,如果不重新编译的话,程序依然能够运行,true null,(我直接用的类,没打包)。其实当你把iface.jar移走后没有重新编译,如果重新编译就能看到会报错的(找不到MyJar)。你使用的应该是旧的class文件。

我估计可能getMyInt()都没有执行,找不到就为null了。

要知道具体原因可能需要打开class文件具体查看一下了。  回复  更多评论   

# re: 一个有趣的现象 2007-07-05 09:56 dennis

getMyInt()是肯定有执行,不信你可以在getMyInt加个
System.out.println("getMyInt()");
看看,原因俺已经说明了,更深入地请看《深入Java虚拟机》,常量池中的MyInt虽然被装载(装载失败),但没有使用,没有被连接、解析并初始化,可以简单地把它当成一个符号罢了  回复  更多评论   

# re: 一个有趣的现象 2007-07-06 09:56 BeanSoft

懒惰加载, 优化过的代码, JVM 会走捷径.  回复  更多评论   

# re: 一个有趣的现象 2007-07-06 11:25 李敏

我没有打包,而是直接运行的。现在说说我的看法。


1 编译好的字节码中可能储存了信息。具体的我也说不出来... !--
2 当你 javac Test的时候,它先是自动搜索当前有无编译好的字节码,如果没有话,才会重新编译,所以它会从之前的字节码中读出信息来参与编译。

可以用一个方法来测试,就是在当前的classpath下,删除掉MyJar.class,MyInt.java更换一个package的时候,就会发现,无法通过编译!

呵呵,不知道我的想法对你有没有帮助!
  回复  更多评论   

# re: 一个有趣的现象 2007-07-06 12:37 dreamstone

@dennis
打包只是为了模拟一个需求。怎么能说没被使用呢
isMyInterface()是调用了getMyInt()的。
执行isMyInterface()没问题,
执行getMyInt()有问题。这个怎么解释,呵呵  回复  更多评论   

# re: 一个有趣的现象 2007-07-06 12:39 dreamstone

@刘明
你可以测试一下,是可以重新编译的。至少在eclipse是可以的。
你可以直接删掉.class文件,让他重新编译出来  回复  更多评论   

# re: 一个有趣的现象 2007-07-06 12:40 dreamstone

@dennis
相对比较赞同这个观点,不过为什么调用getMyInt()会出错呢。根本编译不了。呵呵。  回复  更多评论   

# re: 一个有趣的现象 2007-07-06 12:42 dreamstone

@BeanSoft
好像不是,我取了字节码看,还是有这个接口的。不过考虑可能是load失败,但是判断null==A的时候,根本不管是个什么什么东西,只要知道它不是null就直接得出结论。因为null的==是比较特殊的。不过这也是猜测,没有有力的证明  回复  更多评论   

# re: 一个有趣的现象 2007-07-06 12:46 dreamstone

@李敏
恩,我明白你的意思。不过我说的特殊点在这里:
c是test b是isMyInterface() a是getMyInt()
c调用b b调用a能成功
c直接调用a不能成功。
而且都是putlic static 的函数,  回复  更多评论   

# re: 一个有趣的现象 2007-07-06 13:04 dreamstone

另外提供一个信息,同样的代码和执行方式
在ibm aix上使用ibm sdk得到的结果是不一样的,就是执行isMyInterface() 也出错,呵呵。这个才是起因。  回复  更多评论   

# re: 一个有趣的现象 2007-07-06 17:03 dennis

load失败抛出错误的时间,不同jdk实现不同,有的是一失败就马上给出NoClassDefFoundError,有的是延迟到使用该类的时候再报错。为什么不能调用getMyInt?编译不能通过啊,编译过程中编译器会查找所有出现的符号是否存在。  回复  更多评论   

# re: 一个有趣的现象 2007-07-06 17:04 dennis

这个问题,你再看下《深入java虚拟机》连接和初始化那个章节就明了了  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航: