private T[] elements = new T[initialCapacity];
我能理解为什么.NET不允许我们这样做,因为在.NET中,你有值类型,在运行时可以有不同的大小,但是在Java中,所有类型T都将是对象引用,因此具有相同的大小(如果我说错了,请纠正我)。
这是什么原因呢?
private T[] elements = new T[initialCapacity];
我能理解为什么.NET不允许我们这样做,因为在.NET中,你有值类型,在运行时可以有不同的大小,但是在Java中,所有类型T都将是对象引用,因此具有相同的大小(如果我说错了,请纠正我)。
这是什么原因呢?
这是因为Java的数组(与泛型不同)在运行时包含有关其组件类型的信息。因此,在创建数组时必须知道组件类型。由于您不知道在运行时T
是什么,因此无法创建数组。
ArrayList <SomeType>
是如何实现的呢? - Thumbznew ArrayList<SomeType>()
吗?泛型类型在运行时不包含类型参数,创建时也不使用类型参数。无论是 new ArrayList<SomeType>()
、new ArrayList<String>()
还是 new ArrayList()
生成的代码都没有任何区别。 - newacctArrayList<T>
如何使用它的private T[] myArray
。在代码的某个地方,它必须有一个通用类型为T的数组,那么是如何实现的呢? - ThumbzT[]
的数组。它有一个运行时类型为 Object[]
的数组,要么1)源代码包含一个变量 Object[]
(这是在最新的Oracle Java源代码中的情况);或2)源代码包含一个类型为 T[]
的变量,这是虚假的,但由于 T
在类的作用域内被擦除,所以不会引起问题。 - newacct引用:
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
我认为是Neal Gafter,但不确定。
在此上下文中查看:http://forums.sun.com/thread.jspa?threadID=457033&forumID=316
new T()
相同的原因,甚至不可能执行此操作。在Java中,每个数组都按设计存储其中的组件类型(即T.class
);因此,在运行时需要T的类来创建这样的数组。 - newacctnew Box<?>[n]
,这在某些情况下可能足够,尽管它在你的示例中没有帮助。 - Bartosz KlimekBox<String>[] bsa = new Box<String>[3];
在java-8及以上版本中是否有任何更改? - Eugene在没有提供一个合适的解决方案时,你最终只会得到更糟糕的结果。
通常的解决方法如下。
T[] ts = new T[n];
被替换为(假设T扩展自Object而不是其他类)
T[] ts = (T[]) new Object[n];
我更喜欢第一个例子,但似乎更多学术类型的人更喜欢第二个例子,或者只是不愿意考虑这个问题。
大多数关于为什么不能仅仅使用Object[]的例子同样适用于List或Collection(它们都被支持),所以我认为它们是非常糟糕的论点。
注意:这就是Collections库本身无法编译而出现警告的原因之一。如果这种用例无法在没有警告的情况下得到支持,那么在我的看来,泛型模型本身就存在根本性问题。
String[]
的人(或者如果你将其存储在可公开访问的类型为 T[]
的字段中,然后有人检索它),那么他们将会得到一个 ClassCastException。 - newacctT[] ts = (T[]) new Object[n];
是个不好的想法:https://dev59.com/4KTms4cB2Jgan1znew89 - José Roberto Araújo JúniorT[] ts = new T[n];
是一个有效的例子。我会保留投票,因为他的答案可能会给其他开发人员带来问题和困惑,而且也与主题无关。此外,我将停止对此发表评论。 - José Roberto Araújo Júniornew T[capacity]
将完全不知道需要实例化哪种类型。T t; //Assuming you already have this object instantiated or given by parameter.
int length;
T[] ts = (T[]) Array.newInstance(t.getClass(), length);
T[] ts = t.clone(); for (int i=0; i<ts.length; i++) ts[i] = null;
。 - midniteT[] t
,则应为 (T[]) Array.newInstance(t.getClass().getComponentType(), length);
。我花了一些时间来理解 getComponentType()
。希望这能帮助其他人。 - midnitet.clone()
不会返回 T[]
。因为在这个答案中,t
不是一个数组。 - xmen这里有一个很好的概述在这里。
String[]
强制转换为Object
并在其中存储一个Integer
。所以他们必须添加一个运行时类型检查来防止数组存储(ArrayStoreException
),因为这个问题在编译时无法被捕获。(否则,一个Integer
实际上可能会被卡在String[]
中,当你尝试检索它时就会出现错误,这将是可怕的。) ... - Radon RosboroughObject[]
而不是 Object
。 - Radon RosboroughStack<SomeType>[] stacks = new Stack<SomeType>[2];
由于这是不可能的,所以我采用以下方法作为解决方案:
虽然不太美观,但Java很高兴。
注意:正如BrainSlugs83在问题的评论中提到的那样,在.NET中完全可以有泛型数组。
来自Oracle教程:
在我看来,这听起来很弱。我认为任何具有足够泛型理解的人都会非常好地理解,并且甚至期望在这种情况下不会抛出ArrayStoredException异常。You cannot create arrays of parameterized types. For example, the following code does not compile:
List<Integer>[] arrayOfLists = new List<Integer>[2]; // compile-time error
The following code illustrates what happens when different types are inserted into an array:
Object[] strings = new String[2]; strings[0] = "hi"; // OK strings[1] = 100; // An ArrayStoreException is thrown.
If you try the same thing with a generic list, there would be a problem:
Object[] stringLists = new List<String>[]; // compiler error, but pretend it's allowed stringLists[0] = new ArrayList<String>(); // OK stringLists[1] = new ArrayList<Integer>(); // An ArrayStoreException should be thrown, // but the runtime can't detect it.
If arrays of parameterized lists were allowed, the previous code would fail to throw the desired ArrayStoreException.
我喜欢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();
}
}
}
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)
据我所知,在Java中可以创建通用的数组类型。我是否误解了问题?
class可以声明一个类型为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; }
}