不明白Arrays.copyOf的源代码

Xin*_*Xin 43 java arrays generics

我无法理解源代码Arrays.copyOf.

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}
Run Code Online (Sandbox Code Playgroud)
  1. 这行检查是什么?

    (Object)newType == (Object)Object[].class
    
    Run Code Online (Sandbox Code Playgroud)
  2. (T[]) new Object[newLength]和之间有什么区别(T[]) Array.newInstance(newType.getComponentType(), newLength)?为什么Array.newInstance两种情况都不够好?

  3. 以下行编译,但在运行时崩溃(如预期的那样).我什么时候应该使用这种方法?

    Integer[] nums = Arrays.copyOf(new String[]{"a", "b"}, 2, Integer[].class) 
    
    Run Code Online (Sandbox Code Playgroud)

Rad*_*def 22

这行检查是什么? (Object)newType == (Object)Object[].class

它正在检查简单的相等性(可能是为了进行微优化,但稍后会更多).

不寻常的铸造是必要的,因为Class<Object[]>(类型Object[].class)并且Class<? extends T[]>是无与伦比的类型.基本上,为了与==编译进行相等比较,其中一方必须是另一方的子类型或超类型.

即我们做不到:

// doesn't compile
// this expression can never evaluate to true
(new Integer(0) == new Float(0f))
Run Code Online (Sandbox Code Playgroud)

泛型类型的规则有点复杂,有些情况下比较不能编译,但它仍然可以评估为true.

尽管是所有对象数组类型Class<Object[]>的超类型Class<? extends T[]>,但不是超类型的原因是Java泛型在没有通配符的情况下是不变的.Object[]

另一种进行比较的方法是:

(newType == (Class<? extends Object[]>)Object[].class)
Run Code Online (Sandbox Code Playgroud)

(T[]) new Object[newLength]和之间有什么区别(T[]) Array.newInstance(newType.getComponentType(), newLength)

  • new Object[...]以正常方式创建一个数组,这是一种静态知道的类型.请记住,代码刚刚检查发现T[]Object[].
  • Array.newInstance(...)使用反射动态创建Class传入类型的数组.

为什么Array.newInstance两种情况都不够好?

使用反射的操作通常比其非反射对应物.

反射教程说:

由于反射涉及动态解析的类型,因此无法执行某些Java虚拟机优化.因此,反射操作的性能低于非反射操作,并且应避免在性能敏感应用程序中频繁调用的代码段中.

Java SE充满了像这样的微优化.SE的作者试图从中榨取所有东西.

但在这种情况下我不会担心性能损失:newInstance而且copyOfHotSpot内在函数.这意味着理想情况下对这些方法的调用将被特定于机器的程序集替换.有趣的是,我进行了一些测试,发现之间的差异new Object[...],并Array.newInstance(...)可以忽略不计.问题中的代码可能是遗留物,尽管它可能仍然适用于装备较差的JVM.

在具有严格安全性的某些上下文(例如applet)中也可以禁用反射,但通常不适用于普通的桌面应用程序.

我什么时候应该使用这种方法?

通常,您可能永远不会使用此重载.仅当您想要更改数组的类型时,此重载才有用.

它更典型地使用Arrays.copyOf(T[], int).


Joh*_*ger 14

  1. 这行检查是什么?
(Object)newType == (Object)Object[].class
Run Code Online (Sandbox Code Playgroud)

它正在检查变量是否newType包含对java.lang.Class表示类型实例的引用Object[].演员是不需要的.

  1. (T[]) new Object[newLength]和之间有什么区别(T[]) Array.newInstance(newType.getComponentType(), newLength)?为什么Array.newInstance两种情况都不够好?

据我所知,Array.newInstance() 可以在两种情况下使用,但非反射普通阵列构造可能会快一点.因此,我认为Object[]出于性能原因,这被称为特殊情况,但我不知道这种情况是否经常运行以使优化变得重要.

  1. 以下行编译,但在运行时崩溃(如预期的那样).我什么时候应该使用这种方法?
Integer[] nums = Arrays.copyOf(new String[]{"a", "b"}, 2, Integer[].class) 
Run Code Online (Sandbox Code Playgroud)

当您需要将数组复制到具有可能不同(但兼容)的元素类型的数组时,尤其是当元素类型不是静态知道时,您应该使用它.如果您知道您希望副本具有与原始元素相同的元素类型,那么使用原始数组的clone()方法会更容易.

  • "我不知道这种情况是否经常运行以使优化变得重要" - ArrayList使用copyOf来调整大小.也就是说,Arrays.copyOf在最近的HotSpot版本中是内在化的(由编译器特别识别和处理),因此源代码并不真正相关. (4认同)

Jea*_*ard 6

首先,那条线上的演员阵容

((Object)newType == (Object)Object[].class)
Run Code Online (Sandbox Code Playgroud)

非常需要.删除它们将导致编译错误:

incomparable types: Class<CAP#1> and Class<Object[]>
 where CAP#1 is a fresh type-variable:
  CAP#1 extends T[] from capture of ? extends T[]
Run Code Online (Sandbox Code Playgroud)

现在回答你的问题这行检查是什么?

它只是验证给定的数组是否是对象类型,这是你的另一个问题的答案的一部分为什么Array.newInstance两个案例都不够好?

在第一种情况下,我们已经知道数组是Object类型的,因此调用newInstance方法来检索正确的类型是没有意义的,这只会导致性能损失.

至于你的最后一个例子,

Integer[] nums = Arrays.copyOf(new String[]{"a", "b"}, 2, Integer[].class) 
Run Code Online (Sandbox Code Playgroud)

它确实编译,这是事实.因为该方法的给定参数都是valids.它肯定会在运行时失败; 将"a"转换为Integer类型的预期输出是什么?

现在,何时使用copyOf?当你已经知道这两种类型,并且已经知道它们一起有效时.

它的主要用途是返回一个副本,但用[null/default values]截断或填充到原始数组.


Evg*_*eev 5

  1. 它正在检查newType是否为Objects数组:

    Object[] a1 = new Object[100]; -- array of Objects
    
    String[] a2 = new String[100]; -- array of Strings
    
    Run Code Online (Sandbox Code Playgroud)

为什么这样做?因为新的Object [n]比Array.newInstance快

  1. Array.newInstance(Class<?> componentType, int... dimensions)创建由第一个参数定义的类型数组,例如String.class- > String[].请注意String[].class.getComponentType()返回String.class

  2. 你不能这样使用它,但它可以是这样的

    Integer[] nums = Arrays.copyOf(new Object[]{1, 2}, 2, Integer[].class);
    
    Run Code Online (Sandbox Code Playgroud)

在这种情况下,它仅取决于元素的实际类型,例如

  Arrays.copyOf(new Object[]{1L, 2}, 2, Integer[].class);
Run Code Online (Sandbox Code Playgroud)

会失败,你不能写Integer[]任何东西,但Integer