Bootstrap

Java的<? super T>和<? extends R>理解与应用

记录:293

场景:Java的<? super T>和<? extends R>理解与应用。<? super T>:表示?匹配的类型都是T的父类,包括T本身。<? extends R>:表示?匹配的类型都是类型R的子类,包括R本身。

版本:

JDK 1.8
Spring Boot 2.6.3

一、基础

1.对<? super T>和<? extends R>理解

对<? super T>和<? extends R>理解,就是对泛型的理解。

1.1 概念理解

<? super T>:表示?匹配的类型都是T的父类,包括T本身。

<? extends R>:表示?匹配的类型都是类型R的子类,包括R本身。

1.2 使用List协助理解

1.2.1 List<? extends R>

List<? extends R> list:表示集合中存放的都是R的子类(包括R本身)。

针对变量List<? extends R> list。

(1)对List做添加(add(R))操作,必须使用R或者R的子类添加到list中。

(2)对List做遍历查询操作,必须使用R遍历list,取出元素.

小结:拿到一个变量使用? extends R修饰时,应该是对该变量做查询或取元素操作,不做添加操作。这种方式修饰叫做get原则。

1.2.2 List<? super T>

List<? super T> list:表示集合中存放的都是T的父类(包括T本身)。

针对变量List<? super T> list。

(1)对List做添加(add(T))操作,必须使用T或者T的子类添加到list中。

(2)对List做遍历查询操作,必须使用T父类去遍历list,取出元素。

小结:拿到一个变量使用? super T修饰时,应该是对该变量做添加操作,不做查询操作。这种方式修饰叫做put原则。

二、应用

应用实例来理解:List<? extends R>和List<? super T>

1.应用List<? extends R>

1.1 应用说明

Obj0101是Obj01的子类。

(1)在List<? extends Obj01> list中存放的是Obj01的所有子类(包括Obj01自身)。

(2)f1_1函数的入参是List<? extends Obj01> list,在f1_1函数中,对变量list添加元素会报错,无法确定是哪个子类,因为list存放的任何Obj01子类。

(3)在f1_1函数中,可以对变量list使用Obj01类型取出元素,因为list中的元素都是Obj01的子类(包括Obj01自身)。

(4)在f1_1函数中,针对<? extends Obj01>修饰的变量List,可以读取元素不能添加元素,也被叫做Get原则。

(5)小结:在函数中使用<? extends Obj01>修饰的变量list。

    添加操作:添加元素类型必须是Obj01子类或者自身。比如本例添加子类Obj0101,在f1_1函数之外操作。

    获取操作:获取元素必须遍历List<Obj01>或者List<Object>,在f1_1函数中操作。

先对List<? extends Obj01> list做添加操作,再把值传递给f1_1函数。

1.2 应用实例

应用实例,验证。

/**
 * 给List<? extends R>修饰的变量传值
 * List<? extends R>:表示集合中存放的都是R的子类
 */
public static void f1() {
  // 子类
  List<Obj01> list = new ArrayList<>();
  list.add(new Obj0101("张一"));
  list.add(new Obj0101("王二"));
  f1_1(list);
  // 自身
  List<Obj01> list2 = new ArrayList<>();
  list2.add(new Obj01());
  f1_1(list2);
}

/**
 * 1.在List<? extends Obj01> list中存放的是Obj01的所有子类(包括Obj01自身)。
 * 2.f1_1函数的入参是List<? extends Obj01> list,在f1_1函数中,对变量list添加元素会报错,无法确定是哪个子类,因为list存放的任何Obj01子类。
 * 3.在f1_1函数中,可以对变量list使用Obj01类型取出元素,因为list中的元素都是Obj01的子类(包括Obj01自身)。
 * 4.针对<? extends Obj01>修饰的变量List,可以读取元素不能添加元素,也被叫做Get原则。
 * 5.小结: 在函数中使用<? extends Obj01>修饰的变量list,
 * 添加操作:添加元素类型必须是Obj01子类或者自身。比如本例添加子类Obj0101。
 * 获取操作:获取元素必须遍历List<Obj01>或者List<Object>。
 */
public static void f1_1(List<? extends Obj01> list) {
  for (Obj01 var : list) {
      var.getGirl();
  }
  for (Object var : list) {
      Obj01 obj01 = (Obj01) var;
      obj01.getGirl();
  }
}

2.应用List<? super T>

2.1 应用说明

Obj0201和Obj0202是Obj02的子类。

(1)在List<? super Obj0201> list存放的都是Obj0201的父类(包括自身)

(2)在f2_1函数的入参是List<? super Obj0201> list,在在f1_2函数,对变量list添加Obj0201的子类(包括Obj0201自身)可以的。

(3)在f2_1函数中,对变量变量List<? super Obj0201> list,使用Obj0201或者Obj0201子类取出元素是不行的,会报错,无法确定具体取出的是那种类型。

(4))在f2_1函数中,针对<? super Obj0201>修饰的变量list,可以添加元素不能读取元素,也被叫做Put原则。

(5)总结:

    添加操作:添加元素类型必须是Obj0201子类或者自身,在f2_1函数之中操作。

获取操作:获取元素必须遍历List<Obj02>或者List<Object>,在f2_1函数之外操作。

先定义一个满足List<? super Obj0201> list类型的变量,再把值传递给f2_1函数,在f2_1函数中做添加操作。

2.2 应用实例

应用实例,验证。

/**
 * 给List<? super T>修饰的变量传值
 * ListList<? super T>:表示集合中存放的都是T的父类
 */
public static void f2() {
  List<Obj02> list = new ArrayList<>();
  List<? super Obj0201> list2 = f2_1(list);
  for (Obj02 var : list) {
      var.getGirl();
  }
}

/**
 * (1)在List<? super Obj0201> list存放的都是Obj0201的父类(包括自身)
 * (2)在f2_1函数的入参是List<? super Obj0201> list,在在f1_2函数,对变量list添加Obj0201的子类(包括Obj0201自身)可以的。
 * (3)在f2_1函数中,对变量变量List<? super Obj0201> list,使用Obj0201或者Obj0201子类取出元素是不行的,会报错,无法确定具体取出的是那种类型。
 * (4))在f2_1函数中,针对<? super Obj0201>修饰的变量list,可以添加元素不能读取元素,也被叫做Put原则。
 * (5)总结:
 * 添加操作:添加元素类型必须是Obj0201子类或者自身,在f2_1函数之中操作。
 * 获取操作:获取元素必须遍历List<Obj02>或者List<Object>,在f2_1函数之外操作。
 * 先定义一个满足List<? super Obj0201> list类型的变量,再把值传递给f2_1函数,在f2_1函数中做添加操作。
 */
public static List<? super Obj0201> f2_1(List<? super Obj0201> list) {
  list.add(new Obj0201("刘五"));
  list.add(new Obj0201("陈六"));
  list.add(new Obj0202("赵七"));
  list.add(new Obj0202("张八"));
  return list;
}

3.应用对象

3.1 Obj01基类

public static class Obj01 {
  public Obj01() {
  }
  public void getGirl() {
  }
}

3.2 Obj0101是Obj01子类

public static class Obj0101 extends Obj01 {
  private String name;
  public Obj0101(String name) {
      this.name = name;
  }
  @Override
  public void getGirl() {
      System.out.println(this.name + ",真漂亮.");
  }
}

3.3 Obj02基类

public static class Obj02 {
  private String name;
  public Obj02(String name) {
      this.name = name;
  }
  public void getGirl() {
      System.out.println(this.name + ",真漂亮.");
  }
}

3.4 Obj0201是Obj02子类

public static class Obj0201 extends Obj02 {
  public Obj0201(String name) {
      super(name);
  }
}

3.5 Obj0202是Obj0201子类

public static class Obj0202 extends Obj0201 {
  public Obj0202(String name) {
      super(name);
  }
}

以上,感谢。

2022年8月21日

;