我无法在 Java 中创建泛型数组类型的原因是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2927391/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the reason I can't create generic array types in Java?
提问by devoured elysium
What's the reason why Java doesn't allow us to do
Java不允许我们这样做的原因是什么
private T[] elements = new T[initialCapacity];
I could understand .NET didn't allow us to do that, as in .NET you have value types that at run-time can have different sizes, but in Java all kinds of T will be object references, thus having the same size (correct me if I'm wrong).
我可以理解 .NET 不允许我们这样做,因为在 .NET 中,您的值类型在运行时可以具有不同的大小,但在 Java 中,所有类型的 T 都将是对象引用,因此具有相同的大小(如果我错了纠正我)。
What is the reason?
是什么原因?
采纳答案by newacct
It's because Java's arrays (unlike generics) contain, at runtime, information about its component type. So you must know the component type when you create the array. Since you don't know what T
is at runtime, you can't create the array.
这是因为 Java 的数组(与泛型不同)在运行时包含有关其组件类型的信息。所以在创建数组的时候一定要知道组件类型。由于您不知道T
运行时是什么,因此无法创建数组。
回答by GaryF
回答by Bart Kiers
Quote:
引用:
Arrays of generic types are not allowed because they're not sound. The problem is due to the interaction of Java arrays, which are not statically sound but are dynamically checked, with generics, which are statically sound and not dynamically checked. Here is how you could exploit the loophole:
class Box<T> { final T x; Box(T x) { this.x = x; } } class Loophole { public static void main(String[] args) { Box<String>[] bsa = new Box<String>[3]; Object[] oa = bsa; oa[0] = new Box<Integer>(3); // error not caught by array store check String s = bsa[0].x; // BOOM! } }
We had proposed to resolve this problem using statically safe arrays (aka Variance) bute that was rejected for Tiger.
-- gafter
不允许使用泛型类型的数组,因为它们不合理。问题是由于 Java 数组(不是静态健全的,而是动态检查的)与泛型(静态健全而不是动态检查的)的交互造成的。以下是您如何利用漏洞:
class Box<T> { final T x; Box(T x) { this.x = x; } } class Loophole { public static void main(String[] args) { Box<String>[] bsa = new Box<String>[3]; Object[] oa = bsa; oa[0] = new Box<Integer>(3); // error not caught by array store check String s = bsa[0].x; // BOOM! } }
我们曾提议使用静态安全数组(又名 Variance)来解决这个问题,但被 Tiger 拒绝。
--接班人
(I believe it is Neal Gafter, but am not sure)
(我相信是Neal Gafter,但我不确定)
See it in context here: http://forums.sun.com/thread.jspa?threadID=457033&forumID=316
在此处查看上下文:http: //forums.sun.com/thread.jspa?threadID=457033&forumID=316
回答by Durandal
The reason this is impossible is that Java implements its Generics purely on the compiler level, and there is only one class file generated for each class. This is called Type Erasure.
之所以不可能,是因为Java纯粹在编译器层面实现了它的泛型,每个类只生成一个类文件。这称为类型擦除。
At runtime, the compiled class needs to handle all of its uses with the same bytecode. So, new T[capacity]
would have absolutely no idea what type needs to be instantiated.
在运行时,已编译的类需要使用相同的字节码处理其所有用途。所以,new T[capacity]
绝对不知道需要实例化什么类型。
回答by emory
I like the answer indirectly given by Gafter. However, I propose it is wrong. I changed Gafter's code a little. It compiles and it runs for a while then it bombs where Gafter predicted it would
我喜欢Gafter间接给出的答案。但是,我认为这是错误的。我稍微改变了 Gafter 的代码。它编译并运行了一段时间,然后在 Gafter 预测的地方进行轰炸
class Box<T> {
final T x;
Box(T x) {
this.x = x;
}
}
class Loophole {
public static <T> T[] array(final T... values) {
return (values);
}
public static void main(String[] args) {
Box<String> a = new Box("Hello");
Box<String> b = new Box("World");
Box<String> c = new Box("!!!!!!!!!!!");
Box<String>[] bsa = array(a, b, c);
System.out.println("I created an array of generics.");
Object[] oa = bsa;
oa[0] = new Box<Integer>(3);
System.out.println("error not caught by array store check");
try {
String s = bsa[0].x;
} catch (ClassCastException cause) {
System.out.println("BOOM!");
cause.printStackTrace();
}
}
}
The output is
输出是
I created an array of generics.
error not caught by array store check
BOOM!
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at Loophole.main(Box.java:26)
So it appears to me you can create generic array types in java. Did I misunderstand the question?
所以在我看来你可以在 java 中创建泛型数组类型。我误解了这个问题吗?
回答by Peter Lawrey
By failing to provide a decent solution, you just end up with something worse IMHO.
由于未能提供一个体面的解决方案,你最终只会得到更糟糕的恕我直言。
The common work around is as follows.
常见的解决方法如下。
T[] ts = new T[n];
is replaced with (assuming T extends Object and not another class)
替换为(假设 T 扩展 Object 而不是另一个类)
T[] ts = (T[]) new Object[n];
I prefer the first example, however more academic types seem to prefer the second, or just prefer not to think about it.
我更喜欢第一个例子,但是更多的学术类型似乎更喜欢第二个,或者只是不想考虑它。
Most of the examples of why you can't just use an Object[] equally apply to List or Collection (which are supported), so I see them as very poor arguments.
为什么不能只使用 Object[] 的大多数示例同样适用于 List 或 Collection(受支持),因此我认为它们是非常糟糕的论据。
Note: this is one of the reasons the Collections library itself doesn't compile without warnings. If you this use-case cannot be supported without warnings, something is fundamentally broken with the generics model IMHO.
注意:这是 Collections 库本身不会在没有警告的情况下编译的原因之一。如果您在没有警告的情况下无法支持此用例,那么恕我直言,泛型模型从根本上破坏了某些东西。
回答by Adam
There surely must be a good way around it (maybe using reflection), because it seems to me that that's exactly what ArrayList.toArray(T[] a)
does. I quote:
肯定有一个很好的方法来解决它(也许使用反射),因为在我看来这正是ArrayList.toArray(T[] a)
它的作用。我引用:
public <T> T[] toArray(T[] a)
Returns an array containing all of the elements in this list in the correct order; the runtime type of the returned array is that of the specified array. If the list fits in the specified array, it is returned therein. Otherwise, a new array is allocated with the runtime type of the specified array and the size of this list.
public <T> T[] toArray(T[] a)
以正确的顺序返回一个包含此列表中所有元素的数组;返回数组的运行时类型是指定数组的类型。如果列表适合指定的数组,则在其中返回。否则,将使用指定数组的运行时类型和此列表的大小分配一个新数组。
So one way around it would be to use this function i.e. create an ArrayList
of the objects you want in the array, then use toArray(T[] a)
to create the actual array. It wouldn't be speedy, but you didn't mention your requirements.
所以解决它的一种方法是使用这个函数,即ArrayList
在数组中创建一个你想要的对象,然后toArray(T[] a)
用来创建实际的数组。它不会很快,但你没有提到你的要求。
So does anyone know how toArray(T[] a)
is implemented?
那么有谁知道toArray(T[] a)
是如何实现的?
回答by Ferdi265
The answer was already given but if you already have an Instance of T then you can do this:
答案已经给出,但如果你已经有一个 T 实例,那么你可以这样做:
T t; //Assuming you already have this object instantiated or given by parameter.
int length;
T[] ts = (T[]) Array.newInstance(t.getClass(), length);
Hope, I could Help, Ferdi265
希望,我可以帮忙,Ferdi265
回答by Derek Ziemba
I know I'm a little late to the party here, but I figured I might be able to help any future googlers since none of these answers fixed my issue. Ferdi265's answer helped immensely though.
我知道我参加聚会有点晚了,但我想我可能能够帮助任何未来的谷歌员工,因为这些答案都没有解决我的问题。不过,Ferdi265 的回答帮助很大。
I'm trying to create my own Linked list, so the following code is what worked for me:
我正在尝试创建自己的链接列表,因此以下代码对我有用:
package myList;
import java.lang.reflect.Array;
public class MyList<TYPE> {
private Node<TYPE> header = null;
public void clear() { header = null; }
public void add(TYPE t) { header = new Node<TYPE>(t,header); }
public TYPE get(int position) { return getNode(position).getObject(); }
@SuppressWarnings("unchecked")
public TYPE[] toArray() {
TYPE[] result = (TYPE[])Array.newInstance(header.getObject().getClass(),size());
for(int i=0 ; i<size() ; i++) result[i] = get(i);
return result;
}
public int size(){
int i = 0;
Node<TYPE> current = header;
while(current != null) {
current = current.getNext();
i++;
}
return i;
}
In the toArray() method lies the way to create an array of a generic type for me:
在 toArray() 方法中是为我创建泛型数组的方法:
TYPE[] result = (TYPE[])Array.newInstance(header.getObject().getClass(),size());
回答by Alvin
It is because generics were added on to java after they made it, so its kinda clunky because the original makers of java thought that when making an array the type would be specified in the making of it. So that does not work with generics so you have to do E[] array=(E[]) new Object[15]; This compiles but it gives a warning.
这是因为泛型是在他们制作之后添加到java中的,所以它有点笨拙,因为java的原始制造商认为在制作数组时会在制作时指定类型。所以这不适用于泛型,所以你必须做 E[] array=(E[]) new Object[15]; 这会编译,但会发出警告。