不明白Arrays.copyOf的源码
Do not understand the source code of 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)
正在检查 newType 是否为对象数组:
Object[] a1 = new Object[100]; -- array of Objects
String[] a2 = new String[100]; -- array of Strings
为什么要这样做?因为 new Object[n] 比 Array.newInstance
快
Array.newInstance(Class<?> componentType, int... dimensions)
创建一个由第一个参数定义的类型数组,例如 String.class
-> String[]
。注意 String[].class.getComponentType()
returns String.class
不能这样用,但是可以这样用
Integer[] nums = Arrays.copyOf(new Object[]{1, 2}, 2, Integer[].class);
在这种情况下,它仅取决于元素的实际类型,例如
Arrays.copyOf(new Object[]{1L, 2}, 2, Integer[].class);
会失败,除了Integer
你不能在Integer[]
中写任何东西
- what is this line checking?
(Object)newType == (Object)Object[].class
它正在检查变量 newType
是否持有对表示类型 Object[]
的 java.lang.Class
实例的引用。不需要强制转换。
- What are the differences between
(T[]) new Object[newLength]
and (T[]) Array.newInstance(newType.getComponentType(), newLength)
. why Array.newInstance
not good enough for both cases?
据我所知,Array.newInstance()
可以用于这两种情况,但非反射普通数组构造可能会更快一些。因此,我假设 Object[]
出于性能原因被称为特例,但我不知道这种情况是否足够频繁地被执行以使得优化变得重要。
- This following line compiles, but crashes at run time (as expected). When should I use this method?
Integer[] nums = Arrays.copyOf(new String[]{"a", "b"}, 2, Integer[].class)
当您需要将数组复制到具有可能不同(但兼容)的元素类型的数组时,您应该使用它,尤其是当元素类型不是静态已知的时候。如果您知道您希望副本与原始数组具有相同的元素类型,那么使用原始数组的 clone()
方法会更容易。
让我尝试回答这个问题:
要回答您的第一个问题,它会检查 newType 类型是否与数组中的类型相同。两者也都将类型向上转换为 Object 类型。也就是说,它会尝试查看数组的父类型是否为对象。 See this SO question on Upcasting and Downcasting. My guess is that it casts not because to check for type-safety. Even though all objects in Java derive from objects as a superclass.
注意到
会很有帮助
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 中创建新实例的原因可能是性能选择,如果程序总是必须创建新实例,它将比直接初始化通用对象数组和复制更昂贵事情结束了
Arrays.copyOf 将创建一个新数组(引用旧数组)但具有较新的长度并用空对象填充未使用的位置。 This is what it does on an array of ints 其中用零填充未使用的索引。
Arrays.CopyOf 用于提供对象的浅拷贝,即它引用旧项目,但在 新数组 中。 This SO question has more info on it.
首先是那一行的演员表
((Object)newType == (Object)Object[].class)
绝对需要。删除它们将导致编译错误:
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[]
现在回答你的问题这一行检查的是什么?
它只是验证给定的数组是否为对象类型,这是您另一个问题的部分答案为什么 Array.newInstance
对这两种情况都不够好?
在第一种情况下,我们已经知道数组是 Object
类型,所以调用 newInstance
方法来检索正确的类型是没有意义的,这只会导致性能损失.
至于你最后的例子,
Integer[] nums = Arrays.copyOf(new String[]{"a", "b"}, 2, Integer[].class)
它确实编译,这是真的。因为方法的给定参数都是有效的。它肯定会在运行时失败;将 "a" 转换为 Integer
类型的预期输出是什么?
现在,什么时候使用 copyOf
?当您已经知道这两种类型,并且已经知道它们一起有效时。
它的主要用途是 return 原始数组的副本,但用 [null/default 值截断或填充]。
What is this line checking? (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))
泛型类型的规则有点复杂,在某些情况下比较不会编译,但它仍可能计算为真。
尽管 Object[]
是所有对象数组类型的超类型,但 Class<Object[]>
不是 Class<? extends T[]>
的超类型的原因是 Java generics are invariant 不存在通配符。
另一种比较方法是:
(newType == (Class<? extends Object[]>)Object[].class)
What are the differences between (T[]) new Object[newLength]
and (T[]) Array.newInstance(newType.getComponentType(), newLength)
?
new Object[...]
以正常方式创建一个静态已知类型的数组。请记住,代码刚刚检查了 T[]
是 Object[]
.
Array.newInstance(...)
使用反射动态创建传入的Class
类型数组
Why Array.newInstance
not good enough for both cases?
使用反射的操作比非反射的操作generally slower。
Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.
Java SE 充满了这样的微优化。 SE 的作者试图从中榨取一切。
但在这种情况下我不会担心性能下降:newInstance
and copyOf
are HotSpot intrinsics。这意味着理想情况下,对这些方法的调用将替换为特定于机器的程序集。有趣的是,我 运行 进行了一些测试,发现 new Object[...]
和 Array.newInstance(...)
之间的差异可以忽略不计。问题中的代码可能是遗物,尽管它在装备较差的 JVM 上可能仍然有用。
反射也可以在某些具有严格安全性的上下文中禁用(例如小程序),但通常不会用于普通桌面应用程序。
When should I use this method?
通常,您可能永远不会使用此重载。此重载仅在您想更改数组类型时才有用。
加宽:
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)
比较典型。
我无法理解 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)
正在检查 newType 是否为对象数组:
Object[] a1 = new Object[100]; -- array of Objects String[] a2 = new String[100]; -- array of Strings
为什么要这样做?因为 new Object[n] 比 Array.newInstance
快Array.newInstance(Class<?> componentType, int... dimensions)
创建一个由第一个参数定义的类型数组,例如String.class
->String[]
。注意String[].class.getComponentType()
returnsString.class
不能这样用,但是可以这样用
Integer[] nums = Arrays.copyOf(new Object[]{1, 2}, 2, Integer[].class);
在这种情况下,它仅取决于元素的实际类型,例如
Arrays.copyOf(new Object[]{1L, 2}, 2, Integer[].class);
会失败,除了Integer
Integer[]
中写任何东西
- what is this line checking?
(Object)newType == (Object)Object[].class
它正在检查变量 newType
是否持有对表示类型 Object[]
的 java.lang.Class
实例的引用。不需要强制转换。
- What are the differences between
(T[]) new Object[newLength]
and(T[]) Array.newInstance(newType.getComponentType(), newLength)
. whyArray.newInstance
not good enough for both cases?
据我所知,Array.newInstance()
可以用于这两种情况,但非反射普通数组构造可能会更快一些。因此,我假设 Object[]
出于性能原因被称为特例,但我不知道这种情况是否足够频繁地被执行以使得优化变得重要。
- This following line compiles, but crashes at run time (as expected). When should I use this method?
Integer[] nums = Arrays.copyOf(new String[]{"a", "b"}, 2, Integer[].class)
当您需要将数组复制到具有可能不同(但兼容)的元素类型的数组时,您应该使用它,尤其是当元素类型不是静态已知的时候。如果您知道您希望副本与原始数组具有相同的元素类型,那么使用原始数组的 clone()
方法会更容易。
让我尝试回答这个问题:
要回答您的第一个问题,它会检查 newType 类型是否与数组中的类型相同。两者也都将类型向上转换为 Object 类型。也就是说,它会尝试查看数组的父类型是否为对象。 See this SO question on Upcasting and Downcasting. My guess is that it casts not because to check for type-safety. Even though all objects in Java derive from objects as a superclass.
注意到
会很有帮助 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 中创建新实例的原因可能是性能选择,如果程序总是必须创建新实例,它将比直接初始化通用对象数组和复制更昂贵事情结束了
Arrays.copyOf 将创建一个新数组(引用旧数组)但具有较新的长度并用空对象填充未使用的位置。 This is what it does on an array of ints 其中用零填充未使用的索引。
Arrays.CopyOf 用于提供对象的浅拷贝,即它引用旧项目,但在 新数组 中。 This SO question has more info on it.
首先是那一行的演员表
((Object)newType == (Object)Object[].class)
绝对需要。删除它们将导致编译错误:
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[]
现在回答你的问题这一行检查的是什么?
它只是验证给定的数组是否为对象类型,这是您另一个问题的部分答案为什么 Array.newInstance
对这两种情况都不够好?
在第一种情况下,我们已经知道数组是 Object
类型,所以调用 newInstance
方法来检索正确的类型是没有意义的,这只会导致性能损失.
至于你最后的例子,
Integer[] nums = Arrays.copyOf(new String[]{"a", "b"}, 2, Integer[].class)
它确实编译,这是真的。因为方法的给定参数都是有效的。它肯定会在运行时失败;将 "a" 转换为 Integer
类型的预期输出是什么?
现在,什么时候使用 copyOf
?当您已经知道这两种类型,并且已经知道它们一起有效时。
它的主要用途是 return 原始数组的副本,但用 [null/default 值截断或填充]。
What is this line checking?
(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))
泛型类型的规则有点复杂,在某些情况下比较不会编译,但它仍可能计算为真。
尽管 Object[]
是所有对象数组类型的超类型,但 Class<Object[]>
不是 Class<? extends T[]>
的超类型的原因是 Java generics are invariant 不存在通配符。
另一种比较方法是:
(newType == (Class<? extends Object[]>)Object[].class)
What are the differences between
(T[]) new Object[newLength]
and(T[]) Array.newInstance(newType.getComponentType(), newLength)
?
new Object[...]
以正常方式创建一个静态已知类型的数组。请记住,代码刚刚检查了T[]
是Object[]
.Array.newInstance(...)
使用反射动态创建传入的Class
类型数组
Why
Array.newInstance
not good enough for both cases?
使用反射的操作比非反射的操作generally slower。
Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.
Java SE 充满了这样的微优化。 SE 的作者试图从中榨取一切。
但在这种情况下我不会担心性能下降:newInstance
and copyOf
are HotSpot intrinsics。这意味着理想情况下,对这些方法的调用将替换为特定于机器的程序集。有趣的是,我 运行 进行了一些测试,发现 new Object[...]
和 Array.newInstance(...)
之间的差异可以忽略不计。问题中的代码可能是遗物,尽管它在装备较差的 JVM 上可能仍然有用。
反射也可以在某些具有严格安全性的上下文中禁用(例如小程序),但通常不会用于普通桌面应用程序。
When should I use this method?
通常,您可能永远不会使用此重载。此重载仅在您想更改数组类型时才有用。
加宽:
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)
比较典型。