Java中的铸造成本是多少?避免它是一个好主意吗?

Jac*_*ack 9 java casting

我知道有两种类型的转换是隐式和显式转换.我在StackOverflow上阅读了不同的问题,例如this,this和this,但我仍然想知道在Java中投射的成本是多少,避免它是个好主意?它的最佳实践是什么?

铸造有两种类型:

String s = "Cast";
Object o = s; // implicit casting

Object o = someObject;
String s = (String) o; // explicit casting
Run Code Online (Sandbox Code Playgroud)

在第二种情况下,运行时会产生开销,因为必须检查这两种类型,并且如果转换不可行,JVM必须抛出一个ClassCastException.

有人说最好对应用程序进行分析,以确保铸造是否有用.

Hol*_*ger 18

类型转换通常是一个指标,您应该考虑替代解决方案来解决您的问题.毕竟,在编译时可以检查的所有内容都将有助于程序员.

但是,有时类型转换是不可避免的,在通用代码中,它们经常发生而程序员没有注意到.因此,已经做出了相当大的努力来使类型铸造非常快.

过去,运行时类型转换包括必须遍历超类型层次结构以查找匹配的可能性.今天,类型转换只不过是数字比较加上简单的指针比较,如果没有优化,当分析器可以证明转换总是成功时.

为了快速进行类型转换,每个类都知道它在类层次结构中的深度,并且有一个包含所有超类型的表.要测试一个类,比较它的深度,如果深度较低,则它不能是兼容的类,并且类型转换失败.否则,在等于检查类深度的位置处的表条目必须完全匹配,以便全部进行测试.

例如:

Object o=new JButton();
Container c=(Container)o;
Run Code Online (Sandbox Code Playgroud)

类Container的深度为3,以下是超类表:

Object
Component
Container
Run Code Online (Sandbox Code Playgroud)

类JButton的深度为5,以下是超类表:

Object
Component
Container
JComponent
JButton
Run Code Online (Sandbox Code Playgroud)

现在类型转换检查:

  • JButton深度为5 ? 3,即深度Container,因此测试可能会成功
  • 检查表中的第三个条目,它是完全匹配的:

    Object          Object
    Component       Component
    Container   <=> Container
    JComponent
    JButton
    
    Run Code Online (Sandbox Code Playgroud)

因此不再遍历层次结构,并且类型转换操作相当便宜.

  • 我的答案中的示例是向下转换,因为它是从“对象”转换为“容器”的。但是关于运行时类型检查的要点是,局部变量的类型(这里是“对象”)无关紧要;仅根据转换类型(容器)检查对象的实际类型(此处为JButton)。相比之下,大多数上载操作在编译时就被删除了,它们甚至不生成字节码指令。 (2认同)

ass*_*ias 6

在第二种情况下,运行时会产生开销,因为必须检查两种类型,并且如果转换不可行,JVM必须抛出ClassCastException.

不一定,很有可能对于像这样的简单情况,JIT将能够确定演员将始终有效并将优化支票.运行微基准证实了这一假设:

Benchmark                  Mode  Samples  Score   Error  Units
c.a.p.SO26335959.cast      avgt        5  3.177 ± 0.060  ns/op
c.a.p.SO26335959.noCast    avgt        5  3.174 ± 0.108  ns/op
Run Code Online (Sandbox Code Playgroud)

在更复杂的情况下,分支预测也会对您有利.

底线,像往常一样:衡量,不要猜!


Pee*_*eck 0

如果可能的话,避免铸造。铸造的东西更难维护,因此成本更高 - 如果您需要检查对象,请使用“instanceof”(例如:

if (o instanceof String) {
   // do something
}
Run Code Online (Sandbox Code Playgroud)

JVM 使用它来检查您的对象是否是字符串,并且会返回 true,因为您设置了 o = s)。

如果您稍后在代码中更改类的超类,则强制转换可能不再起作用,并且您需要重新编写代码,而在 instanceof 后面,您可以简单地更改应该检查的类。

//如果我有任何错误,请纠正我。

关于转换时间方面的成本:正如我之前提到的,如果稍后更改代码或更改超类,将会花费大量时间。在运行时方面,由于没有类型安全性,所以进行强制转换,因此检查所需的运行时间会少于由于未经允许的强制转换尝试而导致异常的成本。

  • 没有回答“铸造成本是多少”的问题 (8认同)

归档时间:

查看次数:

10632 次

最近记录:

11 年,11 月 前