1. 无界通配符
”?“表示类型通配符,用于代替具体的类型,它只能在<>中使用,可以解决当具体类型不确定的问题。
语法结构:
public void showFlag(Generic<?> generic) {
}
Generic类的定义:
public class Generic<T> {
private T flag;
public void setFlag(T flag) {
this.flag = flag;
}
public T getFlag() {
return this.flag;
}
}
ShowFlag类,引用generic,用于输出generic的getFlag
public class ShowFlag {
public void show(Generic<?> generic) {
System.out.println(generic.getFlag());
}
}
测试类应用
public class Test {
public static void main(String[] args) {
ShowFlag s = new ShowFlag();
Generic<Integer> generic = new Generic<>();
generic.setFlag(123);
s.show(generic);
Generic<String> generic1 = new Generic<>();
generic1.setFlag("我是小明");
s.show(generic1);
}
}
2. 通配符的上限限定
在java类型中,通配符的上限限定(<? extends 类型>)用于限制泛型的未知类型必须是指定类型的**子类或自身。通过 extends 关键字声明。这种限定能在编译期确保类型安全,同时保留一定的灵活性。
2.1 核心特性
2.1.1 类型范围限制仅允许接收 Type 及其子类的泛型实例。例如 <? extends Number> 可接收 Generic<Integer>、Generic<Double>、Generic<Number>,但不能接收 Generic<String>(因 String 不是 Number 子类)。
例如:ShowFlag类
public class ShowFlag {
public void show(Generic<? extends Number> generic) {
Number flag = generic.getFlag(); // 可以使用Number类型接收了,比较安全
System.out.println(flag);
}
}
使用:
public class Test {
public static void main(String[] args) {
ShowFlag s = new ShowFlag();
Generic<Integer> generic = new Generic<>();
generic.setFlag(123);
s.show(generic);
Generic<String> generic1 = new Generic<>();
generic1.setFlag("我是小明");
s.show(generic1); // 会报错,String不是Number的子类
}
}
2.1.2 “只读” 特性
- 可以**安全读取**:由于确定类型上限,可直接用上限类型接收返回值(如 `Number num = generic.getFlag()`)。
- 不能**写入数据**:编译器无法确定具体类型(可能是 `Integer` 或 `Double` 等),因此禁止调用依赖泛型类型的写入方法(如 `setFlag(? value)` 会报错)。
2.1.3 典型事例
- 类定义
- 上限限定使用
2.1.4 使用场景
- 读取优先的操作:如集合 / 泛型类的遍历、统计等(只需获取数据,无需修改)。
- 限制类型范围:确保操作的对象属于某个继承体系(如处理所有数值类型
Number)。
2.2 上限限定的应用范围
Java 泛型中,上限限定(<? extends 类型> 或 <T extends 类型>)的应用场景非常广泛,可以用于:
- 泛型类
- 泛型接口
- 泛型方法的定义以及方法参数
- 变量声明
等场景,核心是限制泛型类型的范围(必须是指定类型的子类或自身)。以下是具体应用场景:
2.2.1 泛型类 / 接口的定义(类型参数上限)
在声明泛型类或接口时,可通过 <T extends 类型> 限定类型参数 T 的上限,确保 T 只能是指定类型的子类。
作用:限制类 / 接口只能处理特定继承体系的类型,避免传入无关类型(如 NumberContainer<String> 会编译报错)。
2.2.2泛型方法的定义(方法类型参数上限)
在泛型方法中,通过 <T extends 类型> 限定方法的类型参数 T,确保方法接收的参数或返回值属于指定范围。
2.2.3 通配符作为方法参数(<? extends 类型>)
在方法参数中使用通配符上限,允许方法接收多种不同但属于同一继承体系的泛型实例,增强方法的灵活性。
2.2.4变量声明(通配符上限)
声明变量时使用 <? extends 类型>,限制变量只能引用特定范围的泛型实例
2.2.5多边界上限(extends 类型1 & 类型2)
2.3 总结
通配符上限限定(<? extends 类型>)是控制泛型灵活性与安全性的重要手段,核心作用是限制未知类型的范围,并支持安全读取,适合 “消费型” 操作(只获取数据);
上限限定是表示通配符类型是T类或者T类的子类。
3. 通配符的下限限定
在 Java 泛型中,通配符的下限限定(<? super 类型>)用于限制未知类型必须是指定类型的父类或自身,通过 super 关键字声明。与上限限定(<? extends 类型>)的 “只读” 特性不同,下限限定更侧重 “写入” 操作的安全性。
注意:该方法不适用于泛型类。
3.1 基本语法
3.2 核心特性
3.2.1 类型范围限制
仅允许接收 Type 及其父类的泛型实例。例如 <? super Integer> 可接收 Generic<Integer>、Generic<Number>、Generic<Object>(因 Number 是 Integer 的父类,Object 是 Number 的父类),但不能接收 Generic<Byte>(Byte 是 Integer 的同级类,非父类)。
3.2.2 “写入” 特性
- 可以安全写入:由于确定类型下限,可向泛型对象中写入
Type及其子类的实例(编译器确保写入的类型兼容)。 - 读取限制:读取时只能用
Object接收(因未知具体类型是下限的哪个父类)。
3.3 示例
- 类定义
- 下限限定使用
3.4 使用场景
- 写入优先的操作:如向集合 / 泛型类中添加元素(确保添加的元素类型与下限兼容)。
- 消费型方法:方法的主要作用是 “向泛型对象写入数据”,而非读取。
3.5 与上限限定的对比
4. 泛型总结
泛型主要用于编译阶段,编译后的字节码class文件不包含泛型中的类型信息。类型参数在编译后会被替换为Object,运行时虚拟机是不知道泛型的。
使用泛型时几个错误:
- 基本类型不可以用于泛型
- 不可以通过类型参数创建对象