Java不允许我们这么做的原因是什么
private T[] elements = new T[initialCapacity];
我可以理解。net不允许我们这样做,因为在。net中,值类型在运行时可以有不同的大小,但在Java中,所有类型的T都将是对象引用,因此具有相同的大小(如果我错了请纠正我)。
原因是什么?
Java不允许我们这么做的原因是什么
private T[] elements = new T[initialCapacity];
我可以理解。net不允许我们这样做,因为在。net中,值类型在运行时可以有不同的大小,但在Java中,所有类型的T都将是对象引用,因此具有相同的大小(如果我错了请纠正我)。
原因是什么?
当前回答
正如其他人已经提到的,你当然可以通过一些技巧来创造。
但不建议这样做。
因为类型擦除,更重要的是数组中的协方差,它允许子类型数组被赋给超类型数组,这迫使你在试图取回值时使用显式类型强制转换,导致运行时ClassCastException,这是泛型试图消除的主要目标之一:在编译时进行更强的类型检查。
Object[] stringArray = { "hi", "me" };
stringArray[1] = 1;
String aString = (String) stringArray[1]; // boom! the TypeCastException
一个更直接的例子可以在Effective Java: Item 25中找到。
协方差:如果S是T的子类型,则类型S[]的数组是T[]的子类型
其他回答
类可以声明类型为T[]的数组,但它不能直接实例化这样的数组。相反,一种常见的方法是实例化一个Object[]类型的数组,然后对类型T[]进行窄化转换,如下所示:
public class Portfolio<T> {
T[] data;
public Portfolio(int capacity) {
data = new T[capacity]; // illegal; compiler error
data = (T[]) new Object[capacity]; // legal, but compiler warning
}
public T get(int index) { return data[index]; }
public void set(int index, T element) { data[index] = element; }
}
这是因为泛型是在他们创建后才添加到java的,所以它有点笨拙,因为java的原始创造者认为在创建数组时,类型应该在创建时指定。这对泛型不起作用,所以你必须这么做 E[] array=(E[]) new Object[15]; 这将编译,但会给出警告。
肯定有一个好方法(可能是使用反射),因为在我看来,这正是数组列表。toArray(T[] a)可以。我引用:
public <T> T[] toArray(T[] a) 返回一个数组,其中包含所有 此列表中的元素按正确顺序排列;的运行时类型 返回的数组是指定数组的数组。如果列表符合 指定的数组,则在其中返回。否则,新数组为 的运行时类型分配 这个列表。
因此,一种方法是使用这个函数,即创建一个数组中你想要的对象的数组列表,然后使用toArray(T[] a)来创建实际的数组。不会很快,但你没提你的要求。
有人知道toArray(T[] a)是如何实现的吗?
这是不可能的,因为Java完全在编译器级别上实现了泛型,并且每个类只生成一个类文件。 这叫做类型擦除。
在运行时,已编译的类需要用相同的字节码处理它的所有使用。因此,new T[capacity]将完全不知道需要实例化什么类型。
在我的例子中,我只是想要一个堆栈数组,就像这样:
Stack<SomeType>[] stacks = new Stack<SomeType>[2];
由于这是不可能的,我使用了以下作为解决方案:
创建一个非泛型包装器类围绕堆栈(例如MyStack) MyStack[] stacks = new MyStack[2]工作得很好
丑陋,但Java是快乐的。
注意:正如BrainSlugs83在问题的评论中提到的,在.NET中完全可以有泛型数组