7

我已经反编译了一个类,javap并且在常量池部分看到了一些重复项,如下所示:

 #19 = Class              #350          //  java/lang/StringBuilder
... Some other class constants here
#318 = Class              #350          //  java/lang/StringBuilder

Methodrefs 仅引用其中之一:

 #20 = Methodref          #19.#351      //  java/lang/StringBuilder."<init>":()V
 #22 = Methodref          #19.#353      //  java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 #24 = Methodref          #19.#355      //  java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
 #25 = Methodref          #19.#356      //  java/lang/StringBuilder.toString:()Ljava/lang/String;
#110 = Methodref          #19.#445      //  java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;

根据类文件格式,这个类是否正确?我认为每个 Class 只被提及一次,稍后通过它在字节码部分的索引来引用。

$ javac -version
javac 1.7.0_15

另一个奇怪的事情是在 javac Pool.java中代表常量池的类的源代码中。这表明如果对象已经存在(在 HashMap 的帮助下),它将不会将对象放入池中。我想知道这些类的 equals()/hashCode() 方法是否正确实现。

4

3 回答 3

3

正如我从 JVM 规范中了解到的那样,没有这样的限制可以防止常量池中的重复条目。通常,生成类文件的编译器没有重复项。但即使类文件有重复项,也不应该影响其预期行为。

您反编译的类文件是如何创建的?

于 2013-05-24T07:50:05.383 回答
2

你说的对。Constant pool不需要重复条目。一个类在常量池中应该只有 1 个条目。

这绝对似乎是一个错误。看一下这个。有人将此记录为错误并已得到确认>> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6746955

答案更新:

我想在这里指出的另一件事是,添加重复条目没有任何意义,因为它会增加类文件的字节大小,并且破坏了 java 类文件的紧凑性、可移植性和更快的网络移动性的主要目的。类文件应尽可能紧凑。

顺便说一下,类文件是有效的,因为它遵循定义的类文件格式。但它不是一个理想的。

我忘了,回答你的第二个问题:

JVM 为外观相似的对象分配相同的哈希码,但它们仍然是不同的。JVM 永远不会创建两个相同的对象,除非它们都引用同一个对象。哈希码只不过是一个分区系统。看起来相似的对象被放置在同一个分区中,以便在搜索特定对象时遍历时间变得更少。哈希码只不过是指向那个小分区的指针。

只是因为不可能为每个新对象分配不同的哈希码(因为对象的数量可能超过可能创建的唯一哈希码的数量。请参阅哈希算法中可能发生的冲突),您可能会发现具有相同哈希码的不同对象。但事情是这样的,指向内存中相同引用的 2 个对象必须具有相同的哈希码。

因此,从故事的寓意来看,JVM 确保两个不同的对象永远不会相同,即使它们的哈希码相同。

于 2013-05-24T08:48:49.997 回答
0

注意:根据JENKINS-22525,虽然具有此类重复的类文件在技术上是合法的,但 IBM 的 J9 VM 在某些情况下会拒绝加载其内部类,观察到

java.lang.IncompatibleClassChangeError: incompatible InnerClasses attribute between …
于 2014-07-31T16:53:08.207 回答