如何在java中创建List >?

11 浏览
0 Comments

如何在java中创建List >?

来自 Joshua Bloch 的《Effective Java》,

  1. 数组与通用类型有两个重要的不同之处。首先,数组是协变的。通用类型是不变的。
  2. 协变意味着如果 X 是 Y 的子类型,则 X[] 也将是 Y[] 的子类型。数组是协变的。因为字符串是对象的子类型,所以

    String[] 是 Object[] 的子类型

    不变意味着无论 X 是否是 Y 的子类型,

     List will not be subType of List.
    

我的问题是为什么在 Java 中决定使数组协变?有其他的 SO 帖子,如《为什么数组是不变的,但列表是协变的?》,但它们似乎专注于 Scala,我无法理解。

admin 更改状态以发布 2023年5月23日
0
0 Comments

原因是每个数组在运行时都知道其元素类型,而通用集合由于类型擦除而不知道。

例如:

String[] strings = new String[2];
Object[] objects = strings;  // valid, String[] is Object[]
objects[0] = 12; // error, would cause java.lang.ArrayStoreException: java.lang.Integer during runtime

如果通用集合允许这样做:

List strings = new ArrayList();
List objects = strings;  // let's say it is valid
objects.add(12);  // invalid, Integer should not be put into List but there is no information during runtime to catch this

但当某人尝试访问列表时,这将会引起问题:

String first = strings.get(0); // would cause ClassCastException, trying to assign 12 to String

0
0 Comments

根据维基百科

早期版本的Java和C#不包括泛型(即参数化多态性)。

在这样的情况下,使数组不变规则排除了有用的多态程序。
例如,考虑编写一个对数组进行洗牌的函数,或者编写一个利用 Object.equals 方法测试两个数组是否相等的函数。实现不依赖于存储在数组中的确切元素类型,因此应该可以编写一个函数,它适用于所有类型的数组。易于实现以下类型的函数

boolean equalArrays (Object[] a1, Object[] a2);
void shuffleArray(Object[] a);

但是,如果将数组类型视为不变,则只能在确切类型为 Object [] 的数组上调用这些函数。例如,无法对字符串数组进行洗牌。

因此,Java和C#都将数组类型变为协变。例如,在C#中,string [ ] object [ ] 的子类型,在Java中,String [ ] Object [ ] 的子类型。

这回答了“为什么数组是协变的?”这个问题,或者更准确地说,“为什么当时将数组变为协变?”

当引入泛型时,出于Jon Skeet的这个答案中指出的原因,它们被有意地不协变:

不,List不是List。考虑您可以对List做什么-您可以向其中添加任何动物...包括猫。现在,可以将猫逻辑地添加到一窝小狗中吗?绝对不能。

// Illegal code - because otherwise life would be Bad
List dogs = new List();
List animals = dogs; // Awooga awooga
animals.add(new Cat());
Dog dog = dogs.get(0); // This should be safe, right?

突然,一只非常困惑的猫出现了。

维基百科文章中描述的使数组协变的最初动机不适用于泛型,因为通配符使协变(和反变)的表达成为可能,例如:

boolean equalLists(List l1, List l2);
void shuffleList(List l);

0