gpt4 book ai didi

Java:无法理解非静态方法的类型删除

转载 作者:行者123 更新时间:2023-12-04 06:10:38 26 4
gpt4 key购买 nike

这个问题与类型删除及其对数组的影响有关 SCJP (由 Mughal - 第 3 版,第 726 页)。这是简短的代码:

public class MyStack<E> implements IStack<E> {
// Top of stack.
private Node<E> tos;
// Size of stack
private int numOfElements;

:

// Incorrect version
public E[] toArray3() {
E[] toArray = (E[])new Object[numOfElements];
int i=0;
for (E data : this) {
toArray[i++] = data;
}
return toArray;
}

// Correct version
public E[] toArray4(E[] toArray) {
if (toArray.length != numOfElements) {
toArray = E[])java.lang.reflect.Array.newInstance(toArray.getClass().getComponentType(), numOfElements);
}
int i=0;
for (E data : this) {
toArray[i++] = data;
}
return toArray;
}
}

根据书,方法 toArray3是使用 while 方法的错误版本 toArray4是正确的版本,因为数组是 reifiable type .我在这方面没有问题。但是,我在理解为什么输入参数 E 时遇到了问题。 toArray3 不同和 toArray4 .

这是我如何发现的。假设我有以下内容:
MyStack<Integer> intStack = new MyStack<Integer>();
intStack.push(9);
Integer[] x = intStack.toArray4(new Integer[0]); // clause 1
System.out.println(x.length);
Integer[] y = intStack.toArray4(new Object[0]); // clause 2 - compiler error
System.out.println(y.length);
Integer[] z = intStack.toArray3(); // clause 3
System.out.println(z.length);

一种。对于第 1 条,没问题。 toArray4 中的类型参数 E 似乎是整数。

湾对于第 2 条,错误是说 Integer[]不适用于 Object[] .这是否意味着类型删除 toArray4(E[] toArray)toArray4[Integer[] toArray) ?为什么不是对象[]? (虽然我知道 intStack 已被 Integer 实例化。)

C。对于子句 3,运行时错误是说 Object[]不能分配给 Integer[] .我明白这一点,但为什么现在是类型参数 EtoArray3 Object而不是 Integer ?

我希望 toArray3 的类型参数 E ON 与 toArray4 相同,因为 intStack 的类型参数 E 本身是由 toArray3 和 toArray4 使用的整数类型。

请记住,在 toArray3 的正文中,数组 Object 已被强制转换回 E[] .

最佳答案

这些方法的区别在于toArray4()正在使用反射来获取 Class表示数组的正确组件类型的对象。这确保了类型信息在运行时是已知的,尽管类型删除。

关键是这行toArray4() :

Array.newInstance(toArray.getClass().getComponentType(), numOfElements);

与通用对象不同,数组可以提供它们的组件类型,因为类似于 Integer[]有一个对应的 Class可以检查此信息的对象。

正因为如此, toArray4()实际上实例化了一个 Integer[]对象时 EInteger , 而 toArray3()实例化 Object[]并且调用代码(通过类型删除)尝试将其强制转换为 Integer[] ,正确地导致 ClassCastException .

通常,反射通常用作类型删除的解决方法。

需要注意的是,Java 中的数组往往具有与之相关的某些“魔法”,尤其是在反射方面。例如,如果您查看 Class#getComponentType() 的来源和 Array.newInstance()它们都导致 native 代码。

编辑:我认为您困惑的根源是在 toArray3() 中完成的类型转换:
E[] toArray = (E[])new Object[numOfElements];

这不是导致您 ClassCastException 的类型转换.相反,它是通过类型删除添加的第二次转换。为了说明,让我们重写 toArray3()好像已经应用了类型删除:
public Object[] toArray3() {  
Object[] toArray = new Object[numOfElements]; //first cast no longer necessary
int i=0;
for (Object data : this) { //pretend MyStack is no longer generic
toArray[i++] = data;
}
return toArray;
}

然后在调用代码中:
Integer[] z = (Integer[])intStack.toArray3(); //ClassCastException

如您所见, ClassCastException不是在方法中抛出,而是在其结果分配给 z 时抛出使用强制转换,这种类型的删除为您创建。如果您实际发布堆栈跟踪,我们可能会验证这一点。

关于Java:无法理解非静态方法的类型删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7827439/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com