有界类型参数与上界通配符的区别

我知道已经发布了类似的问题,虽然我认为我的情况有所不同……

假设您有两种方法:

// Bounded type parameter private static  void processList(List someList) { } // Upper bound wildcard private static void processList2(List someList) { // ... } 

据我所知,这两个方法都接受参数,即Number 类型ListNumber子类型 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 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 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, Data and Data类型的参数

 public static void add(Data animalData) { } 

下限通配符:

super T :在下限通配符中,只支持T或其超类型。 我们用于定义下限通配符的相同示例。 假设我们将Animal类作为超类或父类,将Dog作为其子类。 现在下面的方法使用下限通配符,只接受类型的参数

 Data, Data and Data public static void add(Data animalData) { } 

无界通配符:

无界通配符支持所有类型。 所以我们上面的示例方法可以采用类型的参数

 Data, Data , Data and Data public static void add(Data animalData) { }