时,当时我们投一个类型的对象到另一个地方的开销?或编译器只是解决了一切,没有成本在运行时?

这是一个普通的事情,或者有不同的情况?

例如,假设我们有对象[],的阵列,其中每个元素可能有不同的类型。但是,我们总是知道肯定说,认为元素0是一个双,元素1是一个字符串。 (我知道这是一个错误的设计,但我们只是假设我不得不这样做。)

是Java类型的信息仍然在运行时保持周围?或者一切编译后遗忘,如果我们这样做(双人间)元素[0],我们就跟着指针和解释这些8个字节的双,不管它是什么?

我对类型如何在Java中做得很不清楚。如果您对书籍或文章,然后感谢任何reccommendation了。

有帮助吗?

解决方案

有2种类型的铸件:

铸造,当从一个类型到更宽的类型,它是自动完成的,并投没有开销:

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

铸造,当从更宽的类型去一个更窄的一个。对于这种情况,你必须明确地使用铸造这样的:

Object o = someObject;
String s = (String) o; // explicit casting

在该第二种情况下,存在开销在运行时,这是因为两种类型的必须检查和在情况下铸造是不可行的,JVM必须抛出ClassCastException。

JavaWorld的摘自:成本铸造的

  

铸造用于之间进行转换   类型 - 参考类型之间在   特别地,对于铸造的类型   操作中,我们感兴趣   这里。

     

向上转型操作(也称为   扩大转换在Java   语言规范)转换一个   子类参考祖先   类引用。该铸造   操作通常是自动的,因为   它总是安全的,可以是   直接由编译器实现。

     

低迷现状操作(也称为   缩小转换在Java   语言规范)的转换   祖先类参考的子类   参考。这种铸造操作   创建执行开销,因为Java的   要求在投检查   运行时间,以确保它是有效的。   如果引用的对象不是   任一所述目标类型的实例   铸造或该类型的一个子类,   尝试投是不允许的   必须抛出   java.lang.ClassCastException。

其他提示

有关一个合理的实现的Java的:

每个对象具有包含报头,除其他事项外,一个指针运行时类型(例如DoubleString,但它不可能是CharSequenceAbstractList)。假定运行时编译器(通常热点Sun的情况下)不能确定类型静态一个一些检查需要由生成的机器代码来执行。

首先该指针运行时类型的需要被读取。这是必要的用于调用在一个类似的情况的虚拟方法反正。

有关浇铸到一个类的类型,已知的是究竟有多少超有直到你击中java.lang.Object,所以类型可以以恒定的距离类型的指针(实际上在热点的前八个)的偏移量被读取。再次,这是类似于读取方法指针的虚拟方法。

然后,将读出的值只需要一个相比于预期的静态类型的演员。根据不同的指令集架构,另一个指令将需要分支(或故障)上的不正确的分支。国际检索单位如32位ARM具有条件指令,并且可以是能够有悲伤路径穿过快乐路径。

接口更难由于接口的多重继承。一般来说,最后两个类型转换接口都缓存在运行时类型。在很早的日子(十年前),接口是一个有点慢,但已不再是相关的。

希望你可以看到这样的事情基本上是无能为力的性能。你的源代码是更重要的。在性能方面,在方案中最大的打击是容易成为高速缓存未命中从追逐对象指针所有的地方(当然类型的信息将是常见的)。

  

例如,假设我们有对象[],的阵列,其中每个元素可能有不同的类型。但是,我们总是知道肯定说,认为元素0是一个双,元素1是一个字符串。 (我知道这是一个错误的设计,但我们只是假设我不得不这样做。)

编译器不注意类型的阵列中的单个元件的。它简单地检查每个元素表达的类型是可分配给数组元素类型。

  

是Java类型的信息仍然在运行时保持周围?或者一切编译后遗忘,如果我们这样做(双人间)元素[0],我们就跟着指针和解释这些8个字节的双,不管它是什么?

的一些信息是在运行时保持周围,而不是静态的类型的单个元件的。您可以从看类文件格式讲这个。

它在理论上是可能的是,JIT编译器可以使用“逃逸分析”,以消除在一些分配不必要类型检查。然而,这样做是为了你的建议将是超越现实的优化的范围程度。分析类型的单个元素的回报将是太小了。

此外,人们不应该写的应用程序代码一样,反正。

在运行时执行铸造的字节代码指令被称为checkcast。您可以使用javap,看看会产生什么指令反汇编的Java代码。

有关阵列,爪哇保持类型信息在运行时。在大多数情况下,编译器将捕获类型错误给你,但也有在那里你会尝试存储对象的数组时碰上ArrayStoreException案件,但类型不匹配(和编译器没抓住)。该 Java语言规范给出了下面的例子:

class Point { int x, y; }
class ColoredPoint extends Point { int color; }
class Test {
    public static void main(String[] args) {
        ColoredPoint[] cpa = new ColoredPoint[10];
        Point[] pa = cpa;
        System.out.println(pa[1] == null);
        try {
            pa[0] = new Point();
        } catch (ArrayStoreException e) {
            System.out.println(e);
        }
    }
}

Point[] pa = cpa是有效的,因为ColoredPoint是点的一个子类,但是pa[0] = new Point()无效。

这是反对一般类型,其中存在保持在运行时没有任何类型的信息。编译器插入checkcast指令,其中必要的。

在打字为通用类型和数组的这种差异使得它常常不适合于混合阵列和通用类型。

在理论上存在从塔顶引入的。 然而,现代的JVM是聪明的。 每一个实现是不同的,但它是不是不合理的假设有可能存在的是JIT优化掉铸造检查时,它可以保证永远不会有冲突的实现。 至于哪些特定的JVM提供这一点,我不能告诉你。我必须承认,我想知道JIT优化自己的细节,但这些都是JVM工程师后顾之忧。

故事的道德是先写可理解代码。如果您遇到速度变慢,配置文件,确定您的问题。 赔率是好的,它不会因铸造。 从不牺牲以试图优化它,直到你知道你需要清洁,安全代码。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top