我的问题如下:
java代码通常会实现泛型集合,如:
public class GenericCollection<T> {
private Object[] data;
public GenericCollection () {
// Backing array is a plain object array.
this.data = new Object[10];
}
@SuppressWarnings( "unchecked" )
public T get(int index) {
// And we just cast to appropriate type when needed.
return (T) this.data[index];
}
}
例如:
for (MyObject obj : genericCollection) {
obj.myObjectMethod();
}
由于genericcollection的泛型类型被删除,jvm似乎无法知道真正在genericcollection的“data”数组中只有myobject示例,因为数组的实际类型是object,所以其中可能有一个字符串,对其调用“myobjectmethod”将引发异常。
所以我假设jvm必须进行一些运行时检查,以了解genericcollection示例中真正的内容。
现在看看这个实现:
public class GenericCollection<T> {
private T[] data;
@SuppressWarnings( "unchecked" )
public GenericCollection ( Class<T> type ) {
// Create a type specific array.
this.data = (T[]) Array.newInstance( type, 10 );
}
public T get ( int index ) {
// No unsafe casts needed.
return this.data[index];
}
}
在本例中,我们通过反射创建一个特定于类型的数组,因此jvm可以推断在给定上下文中该数组中只能有t个对象,这使得不安全的强制转换和可能昂贵的类型检查变得多余。
我的问题是,考虑到hotspot可以做的事情,在性能方面,使用“适当的”特定于类型的支持数组实现泛型集合是否会有所帮助?
例如,它是否有助于消除不必要的类型检查或强制转换?如果它知道backing数组是特定类型的,那么是否可能使它更容易内联方法?
2条答案
按热度按时间72qzrwbm1#
不是在这个特殊的情况下。
泛型数组
T[]
删除为Object[]
在字节码中。的数组getterObject[]
总是回来Object
,因此不需要检查实际的数组类型。因此没有好处T[]
而不是Object[]
用于数组获取操作。在这两种情况下都有aaload
指令后接checkcast
,也是这样。同时,对于类型化数组,数组设置器的性能比
Object[]
,因为aastore
必须检查该值是否与实际数组组件类型匹配。也就是说,你提议的修改同样适用于
get
,但对于set
. 这可以通过以下jmh基准来证实。结果是:
j8ag8udp2#
不,类型擦除java教程解释了
泛型被引入到java语言中,以在编译时提供更严格的类型检查,并支持泛型编程。为了实现泛型,java编译器将类型擦除应用于:
如果泛型类型中的类型参数是无界的,则用它们的边界或对象替换所有类型参数。因此,生成的字节码只包含普通类、接口和方法。
必要时插入类型强制转换以保持类型安全。
生成桥接方法以在扩展泛型类型中保留多态性。
因此,编译之后,泛型类型是
Object
.