ArrayList是如何在Java Collection Framework内部表示的。

时间:2015-04-01 15:08:41

标签: java generics arraylist collections casting

我正在通过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。除了上面的演员之外还有更好的方法吗?

2 个答案:

答案 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。除了上面的演员之外还有更好的方法吗?

取决于“更好”的意思。我已经展示了两种方法以及每种方法的优缺点。