Java泛型–通配符

时间:2020-01-09 10:35:18  来源:igfitidea点击:

在编写通用代码时,我们还可以使用问号(?)作为类型,该类型代表未知类型,在Java泛型中称为通配符。

Java泛型和类关系中的通配符

我们可以使用通配符在通用类或者接口之间创建关系。

如果是非通用类

class A { /* ... */ }
class B extends A { /* ... */ }

我们可以将子类的引用分配给父类。

B b = new B();
A a = b;

但是,相同的分配不适用于泛型类型。

List<B> lb = new ArrayList<>();
List<A> la = lb;   // compile-time error

因此,即使A是父类,List <B>也不是List <A>的子类型。

我们也可以使用整数列表(List <Integer>)和数字列表(List <Number>)来理解它,其中Number是Integer的父类,但List <Integer>实际上不是List <Number>的子类型。 ,这两种类型无关。 List <Number>和List <Integer>的公共父级是List <?>。未知类型的列表,可以是List <Integer>,List <A>,List <String>等。

利用对两个通用类的公共父级的了解,我们将了解如何使用三种通配符在两个通用类(或者接口)之间创建有限关系。

Java泛型中的通配符类型

根据要施加在两个通用类之间的关系的限制,存在三种类型的通配符。

  • 上限通配符

  • 下界通配符

  • 无限通配符

上限通配符

要声明上限通配符,请使用通配符('?'),后接extends关键字,后跟充当上限的类型。上限通配符匹配上限类型或者其任何子类。
例如List <?扩展Number>匹配Number类型或者其任何子类的列表,即List <Integer>,List <Double>,List <Number>。

上限通配符Java示例

假设我们想编写一个可以添加传递的列表的所有元素的方法。由于必须添加元素,因此List应该具有Integer,Float,Double类型的元素,因为Number是所有这些包装器类的超类,因此我们可以使用Number类创建上限。

import java.util.Arrays;
import java.util.List;

public class WildCard {
  public static void main(String[] args) {
    List<Integer> li = Arrays.asList(1, 2, 3, 4);
    System.out.println("sum = " + addListElements(li));
    //List<Double>
    List<Double> ld = Arrays.asList(1.1, 2.2, 3.3, 4.4);
    System.out.println("sum = " + addListElements(ld));
  }
    
  public static double addListElements(List<? extends Number> list){
    double s = 0.0;
    for (Number n : list) {
      s += n.doubleValue();
    }
    return s;
  }
}

输出:

sum = 10.0
sum = 11.0

下界通配符

下限通配符使用通配符('?')表示,后跟super关键字,后跟下限。例如

<?超级A>

下界通配符将未知类型限制为特定类型或者该类型的超类型。例如,我们要编写一种适用于Integer列表和Integer的超类型(例如Integer,Number和Object)的方法,然后我们可以指定一个下界通配符,例如:

列表<?超级整数>

下界通配符Java示例

假设我们要编写一种方法,该方法可以在列表的末尾插入整数,并且可以是"对象列表","数字列表"或者"整数列表",然后可以使用Integer类创建下限。

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

public class WildCard {
  public static void main(String[] args) {
    // with List<Object>
    List<Object> lo = new ArrayList<Object>();
    insertNumbers(lo);
    
    // with List<Number>
    List<Number> ln = new ArrayList<Number>();
    insertNumbers(ln);
    
    // with List<Integer>
    List<Integer> li = new ArrayList<Integer>();
    insertNumbers(li);
  }
    
  public static void insertNumbers(List<? super Integer> list) {
    for (int i = 1; i <= 10; i++) {
      list.add(i);
    }
    System.out.println("Elements in List- " + list);
  }
}

输出:

Elements in List- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Elements in List- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Elements in List- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Java泛型中的无界通配符

使用通配符(?)指定无限制的通配符类型。

例如,List <?>代表未知类型的列表。

无限通配符Java示例

假设我们要编写一个可以打印任何类型的List元素的方法,则应使用List <?>作为方法参数。使用List <Object>不能用作List <Integer>,List <String>,List <Double>不是List <Object>的子类型。

import java.util.Arrays;
import java.util.List;

public class WildCard {
  public static void main(String[] args) {
    // With List<Integer>
    List<Integer> li = Arrays.asList(5, 6, 7);
    printListElements(li);
    // With List<Double>
    List<Double> ld = Arrays.asList(1.2, 3.8, 8.2);
    printListElements(ld);
  }
    
  public static void printListElements(List<?> list){
    for (Object e : list){
      System.out.print(e + " ");
    }
    System.out.println();
  }
}

输出:

5 6 7 
1.2 3.8 8.2