我有一个类MyStack<T>
,它定义了以下
public T[] toArray(){
int s=size();
@SuppressWarnings("unchecked")
T[] result=(T[])new Object[s];
Node n=first;
for (int i=0; i<s; i++){
result[i]=n.data;
n=n.next;
}
return result;
}
由于这会返回一个类型为T
的数组,我认为如果我声明了这个实例:MyStack<String> s=new MyStack<>
,则以下内容完全有效:String[] test=s.toArray()
。我认为这是因为s
类型为String
,toArray
应返回String
类型的数组,因为String
基本上已被替换为T
{1}}在这个类中(我知道这个特定的实例化)。如果我执行此操作,唯一的方法是无错误运行:Object[] test=s.toArray()
。
为什么会这样?
答案 0 :(得分:2)
总之,键入擦除。摘自Java网站:
如果类型参数是无界的,则将泛型类型中的所有类型参数替换为其边界或对象。因此,生成的字节码只包含普通的类,接口和方法。
这意味着,在编译代码时,MyStack<String>
会被编译为MyStack<Object>
。这是为了确保泛型不会因需要创建新类而产生开销。这对你有什么用?以及..
MyStack<String> s = new MyStack<>();
转换为..
MyStack<Object> s = new MyStack<>();
现在,这意味着当您调用toArray
方法时,唯一可以 guarenteed 的类型是Object
类型。编译器无法确定它返回的所有内容都是String
类型,因此由于Java中的强类型,它不会让您将其视为String
。那么,剩下的唯一变量类型是什么?
Object[] array = s.toArray();
额外阅读
答案 1 :(得分:1)
好吧,等一下。假设您的假设是正确的,String
替换了每个T
。
以下演员会有效吗?
String[] result = (String[])new Object[s];
不,它不会。我们可以确定new Object[]
不是String[]
。
现在有时你会看到像(T[])new Object[n]
这样的东西,但它只能起作用,因为强制转换实际上变成了erased在泛型类中。 (这是一种欺骗性的习语。)
当编译类时,实际发生的是T
的引用被替换为其上限(可能是Object
,除非你有类似<T extends ...>
的东西):
public Object[] toArray(){
int s=size();
Object[] result=new Object[s];
Node n=first;
for (int i=0; i<s; i++){
result[i]=n.data;
n=n.next;
}
return result;
}
演员表被移动到呼叫站点:
MyStack stack = new MyStack();
String[] arr = (String[])stack.toArray();
所以实际上,当在类中删除了强制类型转换时,一旦将值返回到类的外部(其中抛出ClassCastException
),就会发生强制转换。
无法一般地实例化数组(和一般对象)是Collections框架定义其toArray
方法以将返回数组作为参数的原因。这个的简单版本如下:
public T[] toArray(T[] inArray){
int s = size();
Node n = first;
for (int i = 0; i < s; i++){
inArray[i] = n.data;
n = n.next;
}
return inArray;
}
有关如何一般创建数组的一些想法,您可能会看到'How to create a generic array in Java?';但是你需要调用者将一些参数传递给方法。