对 Java 中逆变的误解及代码示例
Misunderstanding on Contravariance in Java with code example
我正在尝试一个关于 Java 中逆变的易于理解的示例,但理解有问题。
在下面的示例中,我有 List<? super CarBill> list1
。我的理解是我应该能够添加 CarBill
的任何 superclass 的对象。按照这个逻辑,我应该能够向它添加 Bill
class 的对象,对吗?
我收到编译错误。
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
}
}
My understanding is i should be able to add an object of any superclass of CarBill
没有
A List<? super CarBill>
不是一个可以接受 CarBill
的任何超类型对象的列表。这是一个列表,它将接受 CarBill
的某些 特定 超类型的对象,但它是哪个超类型是未知的。
您可以添加类型 CarBill
的任何对象,因为它保证是类型 ?
的子类型。但是 CarBill
的超类型 而不是 保证是 ?
的子类型。
例如:
List<? super CarBill> myList = new ArrayList<Bill>();
Object o = "Anything";
Object
是 CarBill
的超类型。因此,如果您可以将 CarBill
的任何超类型添加到列表中,您就可以将 o
添加到列表中,这意味着您可以添加 任何到列表。
不完全是。
让我们从这段代码开始:
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!
这一次,您在第三行收到编译器错误:您不能向该列表中添加双精度数。但是,如果你从中读取,你会得到数字(不是对象)。这一切都很好:无论我们尝试什么,上面的代码片段都永远不会编译,因为它试图将双精度值添加到整数列表中。
重点是:List<? extends Number>
不代表:"This list contains numbers, or any subtypes thereof"。不;就像 List x = new ArrayList() 是合法的 java 一样,List<Number>
表示 'this list contains numbers or any subtypes thereof' 因为数字的任何子类型的任何实例本身都可以用作数字。 List<? extends Number>
表示:这是一个列表,仅限于包含某些特定类型的实例,但不知道是哪种类型。已知的是,无论该类型是什么,它要么是 Number 要么是它的某个子类型。
因此,您不能将 任何东西 添加到 List<? extends Number>
。
对于超级,类似的故事:
List<? super CarBill>
表示:这是一个列表,仅限于包含某些特定类型的实例,但不知道是哪种类型。众所周知,无论它是什么类型,它要么是 CarBill 要么是其中的某种 SUPERtype。
这样做的好处是,您可以将 CarBill
个实例添加到 List<? super CarBill>
变量。当你从中读取时,你会得到对象。
你的理解有误。
List<? super CarBill>
表示该列表可以是CarBill
的任何超class或CarBill
本身的列表。可以是List<Object>
,也可以是List<Bill>
,甚至可以是List<CarBill>
。它实际上是哪一个?我们不知道。
因此,您不能将 Bill
添加到 List<? super CarBill>
,因为如果列表实际上是 List<CarBill>
怎么办?您不能将 Bill
添加到 List<CarBill>
。
换句话说,您只能将 CarBill
的 CarBill
或子 class 添加到 List<? super CarBill>
.
如果您打算创建一个可以存储任何类型 Bill
的列表,您可以创建一个 List<Bill>
.
This post 也可能有帮助。
我正在尝试一个关于 Java 中逆变的易于理解的示例,但理解有问题。
在下面的示例中,我有 List<? super CarBill> list1
。我的理解是我应该能够添加 CarBill
的任何 superclass 的对象。按照这个逻辑,我应该能够向它添加 Bill
class 的对象,对吗?
我收到编译错误。
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
}
}
My understanding is i should be able to add an object of any superclass of CarBill
没有
A List<? super CarBill>
不是一个可以接受 CarBill
的任何超类型对象的列表。这是一个列表,它将接受 CarBill
的某些 特定 超类型的对象,但它是哪个超类型是未知的。
您可以添加类型 CarBill
的任何对象,因为它保证是类型 ?
的子类型。但是 CarBill
的超类型 而不是 保证是 ?
的子类型。
例如:
List<? super CarBill> myList = new ArrayList<Bill>();
Object o = "Anything";
Object
是 CarBill
的超类型。因此,如果您可以将 CarBill
的任何超类型添加到列表中,您就可以将 o
添加到列表中,这意味着您可以添加 任何到列表。
不完全是。
让我们从这段代码开始:
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!
这一次,您在第三行收到编译器错误:您不能向该列表中添加双精度数。但是,如果你从中读取,你会得到数字(不是对象)。这一切都很好:无论我们尝试什么,上面的代码片段都永远不会编译,因为它试图将双精度值添加到整数列表中。
重点是:List<? extends Number>
不代表:"This list contains numbers, or any subtypes thereof"。不;就像 List x = new ArrayList() 是合法的 java 一样,List<Number>
表示 'this list contains numbers or any subtypes thereof' 因为数字的任何子类型的任何实例本身都可以用作数字。 List<? extends Number>
表示:这是一个列表,仅限于包含某些特定类型的实例,但不知道是哪种类型。已知的是,无论该类型是什么,它要么是 Number 要么是它的某个子类型。
因此,您不能将 任何东西 添加到 List<? extends Number>
。
对于超级,类似的故事:
List<? super CarBill>
表示:这是一个列表,仅限于包含某些特定类型的实例,但不知道是哪种类型。众所周知,无论它是什么类型,它要么是 CarBill 要么是其中的某种 SUPERtype。
这样做的好处是,您可以将 CarBill
个实例添加到 List<? super CarBill>
变量。当你从中读取时,你会得到对象。
你的理解有误。
List<? super CarBill>
表示该列表可以是CarBill
的任何超class或CarBill
本身的列表。可以是List<Object>
,也可以是List<Bill>
,甚至可以是List<CarBill>
。它实际上是哪一个?我们不知道。
因此,您不能将 Bill
添加到 List<? super CarBill>
,因为如果列表实际上是 List<CarBill>
怎么办?您不能将 Bill
添加到 List<CarBill>
。
换句话说,您只能将 CarBill
的 CarBill
或子 class 添加到 List<? super CarBill>
.
如果您打算创建一个可以存储任何类型 Bill
的列表,您可以创建一个 List<Bill>
.
This post 也可能有帮助。