dev*_*ium 259 java generics type-erasure
Java不允许我们这样做的原因是什么
private T[] elements = new T[initialCapacity];
Run Code Online (Sandbox Code Playgroud)
我可以理解.NET不允许我们这样做,因为在.NET中你有值类型,在运行时可以有不同的大小,但在Java中,所有类型的T都将是对象引用,因此具有相同的大小(如我错了请纠正我).
是什么原因?
new*_*cct 193
这是因为Java的数组(与泛型不同)在运行时包含有关其组件类型的信息.因此,在创建阵列时必须知道组件类型.由于您不知道T运行时的内容,因此无法创建阵列.
Bar*_*ers 134
引用:
不允许使用泛型类型的数组,因为它们不是声音.问题是由于Java数组的交互,这些数组不是静态声音,而是动态检查的,使用泛型,这些泛型是静态的,不是动态检查的.以下是你如何利用这个漏洞:
Run Code Online (Sandbox Code Playgroud)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! } }我们曾提议使用被Tiger拒绝的静态安全阵列(又名Variance)来解决这个问题.
- gafter
(我相信这是Neal Gafter,但我不确定)
请在上下文中查看:http://forums.sun.com/thread.jspa?threadID = 457033&forumID = 316
Pet*_*rey 44
由于未能提供合适的解决方案,您最终会得到更糟糕的恕我直言.
常见的工作如下.
T[] ts = new T[n];
Run Code Online (Sandbox Code Playgroud)
被替换为(假设T扩展Object而不是另一个类)
T[] ts = (T[]) new Object[n];
Run Code Online (Sandbox Code Playgroud)
我更喜欢第一个例子,但是更多的学术类型似乎更喜欢第二个,或者只是不喜欢它.
大多数为什么你不能只使用Object []的例子同样适用于List或Collection(支持),所以我认为它们是非常差的参数.
注意:这是Collections库本身在没有警告的情况下编译的原因之一.如果您在没有警告的情况下无法支持此用例,那么基本上会使用泛型模型恕我直言.
Hum*_*mad 33
数组是协变的
数组被认为是协变的,这基本上意味着,给定Java的子类型规则,T []类型的数组可以包含T类型的元素或T的任何子类型.例如
Number[] numbers = new Number[3];
numbers[0] = newInteger(10);
numbers[1] = newDouble(3.14);
numbers[2] = newByte(0);
Run Code Online (Sandbox Code Playgroud)
但不仅如此,Java的子类型规则还指出,如果S是T的子类型,则数组S []是数组T []的子类型,因此,这样的事情也是有效的:
Integer[] myInts = {1,2,3,4};
Number[] myNumber = myInts;
Run Code Online (Sandbox Code Playgroud)
因为根据Java中的子类型规则,数组Integer []是数组Number []的子类型,因为Integer是Number的子类型.
但是这个子类型规则可能会产生一个有趣的问题:如果我们尝试这样做会发生什么?
myNumber[0] = 3.14; //attempt of heap pollution
Run Code Online (Sandbox Code Playgroud)
最后一行编译得很好,但是如果我们运行这段代码,我们会得到一个ArrayStoreException,因为我们试图将一个double放入一个整数数组中.我们通过Number引用访问数组的事实在这里是无关紧要的,重要的是数组是一个整数数组.
这意味着我们可以欺骗编译器,但我们不能欺骗运行时类型系统.这是因为数组就是我们所说的可再生类型.这意味着在运行时Java知道这个数组实际上是实例化为一个整数数组,它恰好通过Number []类型的引用访问.
因此,正如我们所看到的,有一件事是对象的实际类型,另一件事是我们用来访问它的引用类型,对吧?
Java泛型问题
现在,Java中泛型类型的问题在于编译代码完成后编译器会丢弃类型参数的类型信息; 因此,此类型信息在运行时不可用.此过程称为类型擦除.在Java中实现这样的泛型有很好的理由,但这是一个很长的故事,它与二进制兼容现有代码有关.
这里重要的一点是,由于在运行时没有类型信息,因此无法确保我们不会造成堆污染.
我们现在考虑以下不安全的代码:
List<Integer> myInts = newArrayList<Integer>();
myInts.add(1);
myInts.add(2);
List<Number> myNums = myInts; //compiler error
myNums.add(3.14); //heap polution
Run Code Online (Sandbox Code Playgroud)
如果Java编译器没有阻止我们这样做,那么运行时类型系统也不能阻止我们,因为在运行时没有办法确定该列表应该只是一个整数列表.Java运行时将允许我们将任何我们想要的东西放入此列表,当它应该只包含整数时,因为当它被创建时,它被声明为整数列表.这就是编译器拒绝第4行的原因,因为它不安全,如果允许则可以打破类型系统的假设.
因此,Java的设计者确保我们不能欺骗编译器.如果我们不能欺骗编译器(就像我们可以用数组做的那样)那么我们也不能欺骗运行时类型系统.
因此,我们说泛型类型是不可恢复的,因为在运行时我们无法确定泛型类型的真实性质.
我跳过了这些答案的一些部分你可以在这里阅读全文:https: //dzone.com/articles/covariance-and-contravariance
Fer*_*265 18
已经给出了答案,但如果您已经有一个T实例,那么您可以这样做:
T t; //Assuming you already have this object instantiated or given by parameter.
int length;
T[] ts = (T[]) Array.newInstance(t.getClass(), length);
Run Code Online (Sandbox Code Playgroud)
希望,我能帮助,Ferdi265
主要原因是由于Java中的数组是协变的。
有一个很好的概述这里。
| 归档时间: |
|
| 查看次数: |
151990 次 |
| 最近记录: |