有界类型参数与上界通配符的区别
我知道已经发布了类似的问题,虽然我认为我的情况有所不同……
假设您有两种方法:
// Bounded type parameter private static void processList(List someList) { } // Upper bound wildcard private static void processList2(List someList) { // ... }
据我所知,这两个方法都接受参数,即Number
类型的List
或Number
的子类型 List
。
但毕竟这两种方法有什么区别?
编译期间两种语法之间存在一些差异:
- 使用第一种语法,您可以向
someList
添加元素,但使用第二种语法,则不能。 这通常称为PECS ,通常称为PUT和GET原理。 - 使用第一种语法,你有一个类型参数
T
的句柄,所以你可以使用它来做一些事情,比如在类型T
的方法中定义局部变量,对类型T
引用,调用类中可用的方法由T
等表示。但是使用第二种语法,您没有该类型的句柄,因此您无法执行任何操作。 -
实际上可以从第二种方法调用第一种方法来捕获通配符。 这是通过辅助方法捕获通配符的最常用方法。
private static
void processList(List someList) { T n = someList.get(0); someList.add(1,n); //addition allowed. } private static void processList2(List extends Number> someList) { Number n = someList.get(0); //someList.add(1,n);//Compilation error. Addition not allowed. processList(someList);//Helper method for capturing the wildcard }
请注意,由于generics是编译时糖,因此这些差异在更广泛的层面上仅限于编译。
不同之处在于编译器方面。 在第一个上你可以使用类型(例如用于转换或者使用它作为绑定来调用另一个方法),而在第二个上,你不能使用它。
如果你想使用类型信息,那么请使用有界。 使用通配符时,参数将显示为通用对象,您将无法基于该类型调用方法。
public static ListIterator createListIterator(ListIterator o) { return new ListIteratorAdaptor (o); }
我可以想到以下差异:
a)修改方法内的列表,请考虑以下代码:
private static void processList(List someList) { T t = someList.get(0); if ( t.getClass() == Integer.class ) { Integer myNum = new Integer(4); someList.add((T) myNum); } } // Upper bound wildcard private static void processList2(List extends Number> someList) { Object o = someList.get(0); if ( o instanceof Integer ) { Integer myNum = new Integer(4); someList.add(myNum); // Compile time error !! } }
使用通配符,您无法向列表中添加元素! 编译器告诉你它不知道什么是myNum
。 但是在第一种方法中,您可以通过首先检查T
是否为Integer
,没有编译时错误来添加Integer
。
b)第一种方法称为通用方法。 它遵循为generics方法定义的语法。 方法定义中指定的上限用于限制参数类型。
第二个不一定被称为generics方法,它是接受generics参数的常规方法。 通配符?
with extends
关键字用于放松方法可以接受的类型。
JAVA中通常与Generic一起使用以下三种类型的通配符。 以下通过示例解释每一个。
上限通配符:
? 扩展T :在上限带通配符中,只支持T或其子类型。 例如,我们有一个Animal类,并将Dog,Cat作为其子类型。 因此,遵循通用方法只接受Data
类型的参数
public static void add(Data extends Animal> animalData) { }
下限通配符:
? super T :在下限通配符中,只支持T或其超类型。 我们用于定义下限通配符的相同示例。 假设我们将Animal类作为超类或父类,将Dog作为其子类。 现在下面的方法使用下限通配符,只接受类型的参数
Data, Data and Data
无界通配符:
? :无界通配符支持所有类型。 所以我们上面的示例方法可以采用类型的参数
Data, Data , Data