Just In Time中的bug引起的ClassCastException?

时间:2010-03-11 14:04:07

标签: java aix classcastexception

鉴于这段代码:

public static void writeFile(File file,List buffer)throws IOException{
    File fic = new File(file.getCanonicalPath());
    cat.debug("writing file : "+fic.getAbsolutePath());
    FileOutputStream out = new FileOutputStream(fic);
    PrintStream ps = new PrintStream(out);
    for(int i=0;i<buffer.size();i++){
        ps.println(buffer.get(i));
    }
    ps.flush();
    ps.close();
    out.close();
}

(请不要建议如何安全地关闭流,这是遗留代码,新版本使用try / finally)

我在“ps.println(buffer.get(i))”获得了ClassCastException

这个方法被调用几次(比如5次),其中一个列表只用字符串填充 然后,它被一个填充了String和另一个对象的列表调用(比如ErrorObject) 在我们到达第一个ErrorObject时,我们得到ClassCastException。

com.mycompany.ErrorObject incompatible with java.lang.String

此问题发生在生产环境中,但无法在Dev环境中重现: 产品:jvm = IBM J9 VM 2.4 J2RE 1.6.0 IBM J9 2.4 AIX ppc-32 jvmap3260-20081105_25433(已启用JIT,已启用AOT) Dev:WinXP,JDK 1.6.0_16

这段代码有什么原因可能会失败吗?

最近打了补丁,我担心制作团队没有正确升级jar,但我的老板已经检查过补丁是否已经应用了......

我想知道Just in Time编译器是否可以将ps.println“连接”到ps.println(String)而不是ps.println(Object)。  这可以解释这样的问题,但我不知道这是否可能。

欢迎任何建议,提前谢谢

编辑: 我被问到完整的堆栈跟踪,所以这里是:

java.lang.ClassCastException: com.mycompany.util.ErrorObject incompatible with java.lang.String
    at com.mycompany.util.FileUtils.writeFile(FileUtils.java:91)
    at com.mycompany.util.FileUtils.writeFile(FileUtils.java:50)
    at com.mycompany.itools.task.DBCompareInits.doDBTask(DBCompareInits.java:959)
    at com.mycompany.itools.task.DBTask.doTask(DBTask.java:115)
    at com.mycompany.itools.task.TaskGroup.startGroup(TaskGroup.java:115)
    at com.mycompany.runner.Runner.main(Runner.java:209)

编辑2: javap -c

   65:  invokeinterface #20,  1; //InterfaceMethod java/util/List.size:()I
   70:  if_icmpge   92
   73:  aload   4
   75:  aload_1
   76:  iload   5
   78:  invokeinterface #21,  2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
   83:  invokevirtual   #31; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
   86:  iinc    5, 1
   89:  goto    62
   92:  aload   4
   94:  invokevirtual   #32; //Method java/io/PrintStream.flush:()V
   97:  aload   4
   99:  invokevirtual   #33; //Method java/io/PrintStream.close:()V
   102: aload_3
   103: invokevirtual   #28; //Method java/io/FileOutputStream.close:()V

2 个答案:

答案 0 :(得分:4)

  

我想知道Just in Time编译器是否可以将ps.println“连接”到ps.println(String)而不是ps.println(Object)。这可以解释这样的问题,但我不知道这是否可能。

这是不可能的。或者至少除非存在字节码编译器或JIT编译器错误。如果你有无可辩驳的证据证明是这样的话,你应该只责怪编译器错误。

但是,我要检查的第一件事是正在执行的代码是从您正在查看的源代码编译而来的。确认这一点的一种方法是从源代码重新编译,然后比较在类的各个副本上运行javap的结果。查看字节码还会告诉您字节码编译器要使用的println的哪个重载。

编辑 - javap输出清楚地显示该字节码版本应调用println(Object),并且看不到checkcast操作码。调用错误方法的JIT编译器错误会自动插入代码来进行分类播放,听起来越来越难以理解。

答案 1 :(得分:0)

声明toString()方法,在ErrorObject类中转换为string,并向println()调用添加+“”。像pintln(errorObjList +“”);