我正在通过Robert Sedgewick参加Coursera上的算法讲座。当罗伯特先生指出一个人不能使用Generics with Arrays时,我有点困惑,因为它是不允许的。 但Collection Framework中的ArrayList在内部使用Arrays,允许使用Generic数据类型。我的意思是说我们可以执行以下操作:
ArrayList<Integer> list = new ArrayList<Integer>();
他指出的一个黑客就是:
public class FixedCapacityStack<Item>{
private Item[] s;
private int N = 0;
public FixedCapacityStack(int capacity)
{ s = (Item[]) new Object[capacity];} //this hack
他还提到这是一个丑陋的黑客,必须避免,它也会在编译过程中产生警告。
我的问题是:
1。)ArrayList如何在内部表示各种泛型类型?
2。)如果(假设)他们使用上面提到的hack,为什么在用ArrayList编译程序时它不会产生警告?
3。除了上面的演员之外还有更好的方法吗?
答案 0 :(得分:2)
根据来源:
1 - ArrayList
将项目存储在Object[]
中,并在检索单个元素时强制转换值。实际上有一个@SuppressWarnings("unchecked")
演员阵容发生了。
2 - 这里有两个答案 - 第一个是您(通常)不编译ArrayList
,而是将其包含在JRE / JDK中rt.jar
的类路径中。第二个是ArrayList
在@SuppressWarnings
未经检查的转换为通用类型时使用了Object
。
3 - 您的其他选择(“更好”非常主观)是要求Class
为您的通用类型,并使用Array.newInstance(Class clazz, int capacity)
创建数组,如{{3}中所述}
答案 1 :(得分:1)
1。)ArrayList如何在内部表示各种泛型类型?
你的意思是“内部”是什么意思?泛型仅在编译时存在。 ArrayList
已由其他人为您编译,您只是使用该类文件。所以那里没有泛型。
不同的Java库实现可以以不同的方式编写源代码,但这对您来说并不重要。它“内部”的作用是该类用户不应该关心的内部实现细节。
如果你要编写自己的类FixedCapacityStack
,那么你可以用不同的方式来做:
s
类型为Item[]
的事情,如上所示,并创建Object[]
并投射到Item[]
s
类型为Object[]
并强制转换为Item
请注意,擦除后两种方法都是相同的,因此两者都将编译为完全相同的字节码。区别在于编译时的样式。
第一种方法优于第二种方法的优点是,当你从中获取元素时,它已经是正确的类型,所以你没有到处都有这些丑陋的演员。第一种方法的缺点是从Object[]
到Item[]
的初始演员基本上是一个“谎言”,并且只有在你绝对确保不将s
暴露给在类之外(例如,没有将s
作为类型Item[]
返回的方法);否则你会在意想不到的地方出现类别转换异常。
2。)如果(假设)他们使用上面提到的hack,为什么在用ArrayList编译程序时它不会产生警告?
当您实际编译此类时,只会出现警告。但是,如果它已经编译并且您只是使用类文件。事实上,您通常不会拥有ArrayList
的来源。
3。除了上面的演员之外还有更好的方法吗?
取决于“更好”的意思。我已经展示了两种方法以及每种方法的优缺点。