性能对比:泛型数组与对象数组的get方法效率差异
对比泛型数组与Object数组实现的
get(int)方法效率差异 咱们直接切入主题,这两种实现的核心效率差异,本质上是类型转换的时机和运行时检查开销的区别,下面一步步拆解:
1. GenericArray的实现逻辑与性能表现
class GenericArray<T> { final T[] underlying; GenericArray(Class<T> clazz, int length) { underlying = (T[]) Array.newInstance(clazz, length); } T get(int i) { return underlying[i]; } }
这个类的关键在于初始化阶段就完成了唯一一次类型转换:通过Array.newInstance创建的是对应具体类型的数组(比如传String.class就创建String[]),然后强转为T[]。后续调用get方法时,直接返回数组元素——JVM已经明确知道这个数组的元素类型就是T(或其子类),不需要额外做运行时类型检查,也没有类型转换的额外开销。
2. ObjectArray的实现逻辑与性能表现(补全get方法后)
class ObjectArray<T> { final Object[] underlying; ObjectArray(int length) { underlying = new Object[length]; } T get(int i) { return (T) underlying[i]; } }
这里的性能瓶颈出在get方法里:每次调用都要执行一次运行时类型转换+类型检查。因为underlying是Object[],可以存放任意类型的对象,JVM必须确保要转换的元素确实是T类型(或T的子类),否则就会抛出ClassCastException。这意味着每一次get调用都有额外开销,尤其是在频繁调用(比如循环里反复调用)的场景下,这个开销会被明显放大。
3. 效率差异核心总结
GenericArray:仅在初始化时做一次类型转换,后续所有get调用无额外开销,频繁调用场景下性能更优。ObjectArray:每次get都会触发checkcast字节码指令(执行类型检查),频繁调用时累积开销显著高于前者。
额外细节补充
GenericArray需要传入Class<T>是因为Java泛型是擦除式泛型,运行时没有T的类型信息,必须通过Class对象才能创建具体类型的数组;而ObjectArray不需要这个参数,初始化更简单,但牺牲了性能。- 极端情况下,如果JIT编译器能推断出类型转换绝对安全(比如代码里明确只存放
T类型对象),可能会优化掉ObjectArray的类型检查,但这种优化不具备普遍性,依赖具体代码场景和JVM版本。
内容的提问来源于stack exchange,提问作者user4413257




