5

假设我们有三个(或更多)类

公共类 A {}

公共类 B 扩展 A {}

公共类 C 扩展 B 实现 G {}

假设每个类都有自己的 20 个(或更多)方法。

转换为 C 与转换为 A 对性能的影响更大吗?Java 强制转换是如何在幕后工作的?

向下投射时是否必须通过反射检查所有方法和字段是否存在?

编辑: 类的大小(字段和方法的数量)会影响投射时的性能吗?我对OpenJREDalvik都感兴趣都感兴趣。

作为参考,我知道向上转换可以毫无问题地完成。

4

2 回答 2

4

强制转换的性能取决于 JVM 实现。

JLS 5.5仅确定强制转换的要求(包括递归算法),但没有对实现设置任何要求。实际上5.5.3中的运行时强制转换规则也是以同样的方式确定的。所有产生与建议算法相同结果的 JVM 实现都被接受为适当的 JVM。

通常,C由于 JVM 必须检查对象的运行时类型,因此强制转换为需要更多时间。当施放A它时,没有理由做同样的检查,因为Bextends A

实际上,JVM 并不关心方法和字段的数量。它仅比较类型层次结构,您可以使用反射 ( o.getClass())进行检查

我做了一个示例代码如下,一个向下,然后一个向上:

Object o = new Integer(1);
Integer i = (Integer) o;

Object o2 = i;

编译后的字节码如下:

 0  new java.lang.Integer [16]
 3  dup
 4  iconst_1       <-- 1 as a parameter to the constructor
 5  invokespecial java.lang.Integer(int) [18]   <-- constructor
 8  astore_1 [o]       <-- store in 'o'
 9  aload_1 [o]
10  checkcast java.lang.Integer [16]    <-- DOWNCAST CHECK, SPECIAL BYTECODE
13  astore_2 [i]
14  aload_2 [i]
15  astore_3 [o2]   <-- WITH UPCAST NO CHECK

因此,有一条特定的 JVM 指令可以使用给定的类检查堆栈顶部的元素。

使用 upcast,根本没有检查。

类的大小(字段数、方法数、实际占用空间)无关紧要,因为转换会检查Class(元数据,它实际上是一个对象)。

层次结构级别的数量以及实现接口的数量(如果转换为接口)确实很重要,因为这是要检查的可遍历继承/实现树。

如果此检查没有某种缓存,我会感到惊讶。

于 2013-05-24T18:27:17.893 回答
2

有关 HotSpot 中的详细架构checkcast(在其他响应中提到作为向下转换的 JVM 机制),请查看此会议论文:

HotSpot JVM 中的快速子类型检查

摘要中的引述:

在实际的基准测试运行中,我们的技术基本上一直在 3 条指令(仅 1 条内存引用)中执行完整的子类型检查。在极少数情况下,它会恢复为较慢的阵列扫描。内存使用量适中(每堂课 6 个单词),可以换取时间。

因此,如果您不编写一些非常低级的代码并进行大量转换,则影响可以忽略不计。

于 2015-05-05T08:34:29.180 回答