散装java 散装java
首页
  • Java基础
  • JVM
  • Java多线程
  • 知识点
  • 案例
  • Redis
  • RabbitMQ
  • Kafka
  • Elasticsearch
  • MySQL
  • Linux
  • Docker
  • Zookeeper
  • Nginx
  • Git
  • JMeter
  • Gradle
  • 常见BUG
  • 常见解决方案
  • 资源
  • 问答
💖支持
Gitee (opens new window)
首页
  • Java基础
  • JVM
  • Java多线程
  • 知识点
  • 案例
  • Redis
  • RabbitMQ
  • Kafka
  • Elasticsearch
  • MySQL
  • Linux
  • Docker
  • Zookeeper
  • Nginx
  • Git
  • JMeter
  • Gradle
  • 常见BUG
  • 常见解决方案
  • 资源
  • 问答
💖支持
Gitee (opens new window)
  • Java基础

    • Java 基础导读
    • Java 中运算符的优先级
    • 泛型

      • 什么是泛型擦除
      • 什么是泛型的桥方法
      • 泛型通配符以及边界
        • 泛型的通配符?和 T 的区别
        • 什么是无界通配符
        • List 和 List 有何不同
        • 什么是有界通配符
        • 有什么区别?
        • 有什么区别
  • Java集合

    • ArrayList
    • LinkedList
    • HashMap
  • Java并发-JUC

  • JVM

    • 什么是JVM
    • JVM的组成及其作用
    • 类加载机制&双亲委派
  • Java多线程

    • 多线程导读
  • Java
  • Java基础
  • 泛型
散装java
2022-11-28
目录

泛型通配符以及边界

# 泛型的通配符?和 T 的区别

  1. T 可以用于声明变量或常量而 ? 不行
  2. T 一般用于声明泛型类或方法,通配符 ?一般用于泛型方法的调用代码和形参
  3. T 在编译期会被擦除为限定类型或 0bject,通配符用于捕获具体类型。

# 什么是无界通配符

无界通配符可以接收任何泛型类型数据,用于实现不依赖于具体类型参数的简单方法,可以捕获参数类型并交由泛型方法进行处理。

public static void test1(List<?> list) {
    // todo 业务处理
    System.out.println(list.toString());
}
1
2
3
4

# List 和 List<?> 有何不同

List<?> list 表示 list是持有某种特定类型的List,但是并不知道是具体那种类型,因此我们在往里添加元素的时候会报错。

List list 表示 list 中的元素是 Object 类型的,可以进行对象添加操作

如下

public static void main(String[] args) {
    List list1 = new ArrayList<>();
    List<?> list2 = new ArrayList<>();
    list1.add("散装java");
    // 下面这个报错
    list2.add("散装java");
}
1
2
3
4
5
6
7

# 什么是有界通配符

我们在使用泛型的时候,可以限定泛型的上下边界,如下

// <? extends Number> 上界通配符
public static void test1(List<? extends Number> list) { }
// <? super Number> 下界通配符
public static void test2(List<? super Number> list) { }
1
2
3
4

<? extends Number>上界通配符 要求 ? 必须是Number的子类

<? super Number>下界通配符 要求 ? 必须是Number的父类

也就是说,上述例子中 test1 方法的参数,可以使 ArrayList<Integer>()、ArrayList<Long>() 等等,但是不能是 ArrayList<String>();

而 test2 中,则可以是 ArrayList<Object>(),而不能是 ArrayList<Integer>()

test1(new ArrayList<Integer>());
test1(new ArrayList<Long>());
// 下面的会报错
test1(new ArrayList<String>());

test2(new ArrayList<Object>());
// 下面的会报错
test2(new ArrayList<Long>());
1
2
3
4
5
6
7
8

# <? extends xxx >和 <? super xxx> 有什么区别?

两者接收参数的范围不同。

并且,使用 <? extends xxx>声明的泛型参数只能调用 get()方法返 xxx类型,调用 set()报错。

使用 <? super xxx> 声明的泛型参数只能调用 set() 方法接收 xxx类型,调用 get() 报错。

List<? extends Number> list = new ArrayList<>();
// 这里因为 ? 可能是Number的任何一个子类,所以,你在往里添加数据的时候,它并不能确定
// 因此会抛出异常 ,提示:capture of ? extends Number
list.add(new Double(1));
// 而获取则一定是 Number 的子类, 所以可以用父类来接收
final Number number = list.get(0);
List<? super Number> list2 = new ArrayList<>();
// 这里因为 ? 是 Number 的 父类 ,所以不管你往里面添加什么的数字,一定属于 Number 的子类
list2.add(1);
// 而在获取这个数据的时候, 你并不能确定你拿到的数据是什么。因为 ? 是 Number 的父类 
final Number object = list2.get(0);
1
2
3
4
5
6
7
8
9
10
11

# <? extends xxx> 和 < T extends xxx> 有什么区别

< T extends xxx>用于定义泛型类和方法,擦除后为xxx类型

<? extends xxx>用于声明方法的形参,接收xxx和其子类型

上次更新: 2022/11/28, 19:59:06
什么是泛型的桥方法
ArrayList

← 什么是泛型的桥方法 ArrayList→

Theme by Vdoing | Copyright © 2022-2024 散装java | MIT License | 鲁ICP备2022022143号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式