关于Java中的协方差的误解与代码示例

时间:2019-02-18 08:59:38

标签: java contravariance

我正在尝试一个简单易懂的有关Java逆向的示例,并且对问题有所了解。 在下面的示例中,我有List<? super CarBill> list1。我的理解是,我应该能够添加CarBill的任何超类的对象。通过这种逻辑,我应该能够向其添加Bill类的对象吗? 我收到编译错误。

package Generics;

import java.util.ArrayList;
import java.util.List;

public class VarianceTests {
    static class Bill{
        String vName;
        String type;
        Bill(String vName){
            this.vName=vName;
        }
        Bill(String vName,String type){
            this.vName=vName;
            this.type=type;
        }
    }

    static class CarBill extends Bill{
        String name;
        CarBill(String name)
        {
            super(name,"Car");
        }
    }

    static class Car<T extends Bill> {
        T car;
        Car(T car){
            this.car=car;
        }

        String getNameOfCar() {
            return car.vName;
        }
    }


public static void main(String args[]) {
    CarBill cBill = new CarBill("Baleno");
    Bill bill=new Bill("Whatever");
    Car car = new Car(bill); //cBill is valid too as Car accepts <? extends Bill>

    List<? super CarBill> list1 = new ArrayList<>();
    list1.add(cBill);
    list1.add(bill);
}

public void acceptListOfCars(List<? extends Bill> list1) {
    Bill b = list1.get(0); //Valid syntax

}

}

3 个答案:

答案 0 :(得分:2)

不太。

让我们从以下代码开始:

List<Integer> listOfInts = new ArrayList<Integer>();
List<Number> listOfNumbers = listOfInts;
listOfNumbers.add(5.5D); // a double
int i = listOfInts.get(0); // uhoh!

以上代码实际上不会编译;第二行是无效的分配。您的思路会说:但是..为什么呢? Number是Integer的超类型,因此,整数列表也很容易成为数字列表,不是吗?但是第三行显示了为什么这一行推理不正确。 Java不允许您编写以上代码。您可以写的是:同一件事,但是这次我们调整第二行:

List<Integer> listOfInts = new ArrayList<Integer>();
List<? extends Number> listOfNumbers = listOfInts;
listOfNumbers.add(5.5D); // a double
int i = listOfInts.get(0); // uhoh!

这一次,您在第三行收到编译器错误:您不能在此列表中添加双精度型。但是,如果您从中读取,则会得到数字(而不是对象)。一切都很好:无论我们尝试什么,上面的代码片段都永远都不能编译,因为它试图将双精度数添加到一个int列表中。

要点是:List<? extends Number>并不表示:“此列表包含数字或其任何子类型”。没有;就像List x = new ArrayList()是合法的Java一样,List<Number>的意思是“此列表包含数字或其任何子类型”,因为任何数字子类型的任何实例本身都可以用作数字。 List<? extends Number>的意思是:该列表被限制为仅包含某些特定类型的实例,但该类型未知。众所周知,无论该类型是什么,它都是Number或其子类型。

因此,您不能将任何内容添加到List<? extends Number>

超级,类似的故事:

List<? super CarBill>的含义:这是一个列表,仅限于包含某些特定类型的实例,但该类型未知。已知的是,无论是哪种类型,它都是CarBill或其某些SUPER类型。

这样做的好处是,您可以将CarBill实例添加到List<? super CarBill>变量中。当您从中读取内容时,您会拿出物品。

答案 1 :(得分:2)

您的理解是错误的。

List<? super CarBill>表示该列表可以是CarBillCarBill本身的任何超类的列表。它可能是List<Object>,可能是List<Bill>,甚至可能是List<CarBill>。实际上是哪一个?我们不知道。

因此,您不能将Bill添加到List<? super CarBill>,因为如果列表实际上是List<CarBill>怎么办?您不能将Bill添加到List<CarBill>

换句话说,您只能将CarBillCarBill的子类添加到List<? super CarBill>中。

如果您打算创建一个可以存储任何类型的Bill的列表,则可以创建一个List<Bill>

This post也可能有帮助。

答案 2 :(得分:1)

  

我的理解是,我应该能够添加任何CarBill超类的对象

否。

List<? super CarBill>不是将接受CarBill的任何超类型对象的列表。该列表将接受CarBill的某些 specific 超类型的对象,但是尚不清楚哪个超类型。

您可以添加任何类型为CarBill的对象,因为可以保证它是类型为?的子类型。但是不能保证CarBill的超类型是?的子类型。

例如:

List<? super CarBill> myList = new ArrayList<Bill>();

Object o = "Anything";

ObjectCarBill的超类型。因此,如果您可以在列表中添加 CarBill 的任何超类型,则可以在列表中添加o,这意味着您可以添加任何内容< / em>到列表。