不明白Arrays.copyOf的源代码
我无法理解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; }
-
这一行是什么检查?
(Object)newType == (Object)Object[].class
-
(T[]) new Object[newLength]
和(T[]) Array.newInstance(newType.getComponentType(), newLength)
之间有什么区别。 为什么Array.newInstance
对两种情况都不够好? -
下面这行代码编译,但在运行时崩溃(如预期的那样)。 我应该什么时候使用这种方法?
Integer[] nums = Arrays.copyOf(new String[]{"a", "b"}, 2, Integer[].class)
这行检查是什么?
(Object)newType == (Object)Object[].class
这是检查简单的平等(可能是为了微观优化的目的,但稍后更多)。
因为Class<Object[]>
( Object[].class
)和Class<? extends T[]>
Class<? extends T[]>
是无与伦比的types。 基本上,为了与==
进行等式比较来进行编译,其中一方必须是另一方的子types或超types。
即我们不能这样做:
// doesn't compile // this expression can never evaluate to true (new Integer(0) == new Float(0f))
genericstypes的规则有点复杂,有些情况下比较不能编译,但是仍然可以评估为真。
Class<Object[]>
不是Class<? extends T[]>
的超types的原因 尽pipeObject[]
是所有对象数组types的超types,但Class<? extends T[]>
是因为没有通配符, Javagenerics是不变的。
另一种做比较的方法是:
(newType == (Class<? extends Object[]>)Object[].class)
(T[]) new Object[newLength]
和(T[]) Array.newInstance(newType.getComponentType(), newLength)
什么(T[]) Array.newInstance(newType.getComponentType(), newLength)
?
-
new Object[...]
创build一个静态已知types的常规方法。 请记住,代码刚刚检查过T[]
是Object[]
。 -
Array.newInstance(...)
使用reflection来dynamic创build一个传入的Class
types的数组。
为什么
Array.newInstance
对两种情况都不够好?
使用reflection的操作通常比其非reflection对应物慢 。
反思教程说:
由于reflection涉及dynamicparsing的types,因此无法执行某些Java虚拟机优化。 因此,reflection操作的性能要比非reflection操作的性能要差,应该在对性能敏感的应用程序中频繁调用的代码段中避免。
Java SE充满了这样的微型优化。 SE的作者试图挤出所有可能的东西。
但在这种情况下,我不会担心性能问题: newInstance
和copyOf
是HotSpot内在函数 。 这意味着理想情况下这些方法的调用将被机器特定的组件所取代。 有趣的是,我运行了一些testing,发现new Object[...]
和Array.newInstance(...)
之间的差异可以忽略不计。 问题中的代码可能是遗留的,尽pipe它可能在装备不足的JVM上仍然有用。
也可以通过严格的安全性(如小应用程序)在某些情况下禁用reflection,但通常不能用于正常的桌面应用程序。
我应该什么时候使用这种方法?
一般来说,你可能永远不会使用这个过载。 这个重载只有在你想改变数组的types时才有用。
-
拓宽:
Object[] a = Arrays.copyOf( new String[] { "hello", "world" }, 3, Object[].class); a[2] = Character.valueOf('!'); System.out.println(Arrays.toString(a));
-
缩小:
String[] a = Arrays.copyOf( new Object[] { "hello", "world" }, 2, String[].class); System.out.println(String.join(" ", a));
使用Arrays.copyOf(T[], int)
更为典型。
- 这一行是什么检查?
(Object)newType == (Object)Object[].class
它检查variablesnewType
是否保存对表示Object[]
types的java.lang.Class
实例的引用。 演员是不需要的。
(T[]) new Object[newLength]
和(T[]) Array.newInstance(newType.getComponentType(), newLength)
之间有什么区别。 为什么Array.newInstance
对两种情况都不够好?
据我所知,在这两种情况下都可以使用Array.newInstance()
,但是非reflection的普通数组构造可能会快一点。 因此,我认为由于性能的原因, Object[]
被称为特例,但我不知道这种情况是否被频繁执行,以使优化变得重要。
- 下面这行代码编译,但在运行时崩溃(如预期的那样)。 我应该什么时候使用这种方法?
Integer[] nums = Arrays.copyOf(new String[]{"a", "b"}, 2, Integer[].class)
当需要将一个数组复制到一个可能不同(但兼容)元素types的数组时,应该使用它,特别是当元素types不是静态的时候。 如果您知道您希望副本具有与原始副本相同的元素types,那么使用原始数组的clone()
方法会更容易。
-
它检查newType是否是Object的数组:
Object[] a1 = new Object[100]; -- array of Objects String[] a2 = new String[100]; -- array of Strings
为什么这样做? 因为新的Object [n]比Array.newInstance快
-
Array.newInstance(Class<?> componentType, int... dimensions)
创build由第一个参数定义的types数组,例如String.class
– >String[]
。 请注意,String[].class.getComponentType()
返回String.class
-
你不能像这样使用它,但它可以是这样的
Integer[] nums = Arrays.copyOf(new Object[]{1, 2}, 2, Integer[].class);
在这种情况下,它仅取决于实际types的元素,例如
Arrays.copyOf(new Object[]{1L, 2}, 2, Integer[].class);
会失败,你不能在Integer[]
写入Integer
首先,在这一行中投
((Object)newType == (Object)Object[].class)
是absobuletly需要的。 删除它们将导致编译错误:
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[]
现在回答你的问题这是什么行检查?
它只是validation给定的数组是否是对象types,这是你的其他问题的答案的一部分为什么Array.newInstance
不够好的两种情况?
在第一种情况下,我们已经知道该数组是Object
types的,所以调用newInstance
方法来检索正确的types没有意义,这只会导致性能损失。
至于你最后的例子,
Integer[] nums = Arrays.copyOf(new String[]{"a", "b"}, 2, Integer[].class)
它确实编译,这是真的。 因为这个方法的参数都是valids。 它肯定会在运行时失败; 将“a”转换为Integer
types的预期输出是什么?
现在,什么时候使用copyOf
? 当你已经知道这两种types,并已知道他们在一起有效。
它的主要用法是返回一个副本,但截断或用[null /默认值]填充到原始数组。
让我试着回答这个问题:
为了回答你的第一个问题,它检查newTypetypes是否与数组中的types相同。 两者都将types转换为对象types。 也就是说,它试图查看数组的父types是否是对象。 在上传和下载中看到这个问题 。 我的猜测是,这不是因为检查types安全性。 尽pipeJava中的所有对象都是作为超类派生的。
注意到这将是有帮助的
T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength);
实际上是一条线。 即它实际上是一个if-else条件。
result = (condition) ? (doThisIfTrue) : (elseDoThisIfFalse)
简单的例子
所以基本上这条线将是相同的:
T[] copy; Boolean condition = ((Object)newType == (Object)Object[].class) if(condition) copy = (T[]) new Object[newLength]; else copy = (T[]) Array.newInstance(newType.getComponentType(), newLength);
在Array.newInstance中创build一个新实例的原因可能是性能的select,如果程序总是需要创build新的实例,那么比直接初始化一个通用对象数组和复制东西要花费更多。
Arrays.copyOf将创build一个新的数组(引用旧数组),但是具有更新的长度,并将未使用的位置用空对象填充。 这就是它在一个int数组上进行的操作,它用零填充未使用的索引。
Arrays.CopyOf用于提供对象的浅拷贝,即它指的是旧项目,但在一个新的数组中 。 这个问题有更多的信息。