Java的类型通配符
-
什么是类型通配符?
-
类型通配符一般是使用 “?” 代替具体的类型实参
-
类型通配符是类型实参,而不是类型形参。
-
package com.heima.demo;
//类型通配符
public class Test{
public static void main(String[] args){
Box<Number> box1 = new Box<>();
box1.setFirst(100);
showBox(box1);
Box<Integer> box2 = new Box<>();
box2.setFirst(200);
showBox(box2); //报错,即使Integer继承自Number也不行。
}
public static void showBox(Box<Number> box);{ //box里面的Integer和Number不能通过继承或者多态去理解
Number first = box.getFirst();
System.out.println(first);
}
}
package com.heima.demo;
public class Box<E>{
private E first;
public E getFirst(){
return first;
}
public void setFirst(E first){
this.first = first;
}
}
-
解决方法如下,使用类型通配符:
package com.heima.demo;
//类型通配符
public class Test{
public static void main(String[] args){
Box<Number> box1 = new Box<>();
box1.setFirst(100);
showBox(box1);
Box<Integer> box2 = new Box<>();
box2.setFirst(200);
showBox(box2);
}
public static void showBox(Box<?> box);{ //通配符“?”代表的是泛型实参Number,所以“?”也是实参。
Object first = box.getFirst(); //用Object去接收通配符的返回值,因为通配符是任意类型,但全都包括在Object类下。
System.out.println(first);
}
}
类型通配符的上限
-
语法:
-
类/接口<? extends 实参类型>
-
要求该类泛型的类型只能是实参类型,或者实参类型的子类类型。
-
//修改上方的泛型实参代码,限制box类型通配最大类只能到Number。
//限制只能使用Number或Number的子类
public static void showBox(Box<? extends Number> box){
Number first = box.getFirst();
System.out.println(first);
}
package com.heima.demo;
public class Animal{
public String name;
public Animal(String name){
this.name = name;
}
package com.heima.demo;
public class Cat extends Animal{
public int age;
public Cat(String name, int age){
super(name);
this.age = age;
}
package com.heima.demo;
public class MiniCat extends Cat{
public int level;
public MiniCat(String name, int age, int level){
super(name, age);
this.level = level;
}
package com.heima.demo;
import jaca.util.ArrayList;
/**
*泛型通配符
*/
public class Test08{
public static void main(String[] args){
ArrayList<Animal> animals = new ArrayList<>();
ArrayList<Cat> cats = new ArrayList<>();
ArrayList<MiniCat> miniCats = new ArrayList<>();
showAnimal(animals);//这句会报错
showAnimal(cats);
showAnimal(miniCats);
cats.addAll(animals); //报错,原因如下:
//addAll(Collection<? extends Cat> c) boolean
cats.addAll(cats);
cats.addAll(nimiCats);
}
/**
*泛型类型通配符,传递的集合类型,只能是Cat或它的子类类型。
*@param list
*/
public static void showAnimal(ArrayList<? extends Cat> list){
//list.add(new Animal());
//list.add(new Cat());
//list.add(new MiniCat()); 均会报错
for(int i=0; i < list.size(); i++){
Cat cat = list.get(i); //list.get(i).var
System.out.println(cat);
}
}
}
-
禁止向list内填充元素,因为使用上限通配符的时候ArrayList采用的数据具体类型未知。
-
addAll(Collection<? extends Cat> c) boolean 和 list.add(new Animal()) 不一样,一个是集合中的一个元素添加进另一个集合,另一个是直接往集合里添加元素,不被允许。
类型通配符的下限
-
语法
-
类/接口<?super 实参类型>
-
要求该泛型的类型,只能是实参类型,或实参类型的父类类型。
-
package com.heima.demo;
import java.util.ArrayList;
import java.util.List;
/**
*类型通配符下限,要求集合只能是Cat或Cat的父类类型。
*/
public class Test09{
public static void main(String[] args){
ArrayList<Animal> animals = new ArrayList<>();
ArrayList<Cat> cats = new ArrayList<>();
ArrayList<MiniCat> miniCats = new ArrayList<>();
showAnimal(animals);
showAnimal(cats); //传miniCats这个子类就会报错
}
public static void showAnimal(List<? super Cat> list){
//注意,这个就可以填充元素但不保证元素类型的约束要求。
list.add(new Cat());
list.add(new MiniCat());
//遍历内部元素时全用的顶父类:Object
for(Object o : list){
System.out.println(o);
}
}
}
-
对类型通配符的使用
package com.heima.demo;
/**
*类型通配符下限的使用
*/
public class Test10{
public static void main(String[] args){
//创建TreeSet的时候是可以去给它指定比较器的
//构建子类对象前必然先去构建父类对象
//public TreeSet(Comparator<? super E> comparator){
//this(new TreeMap<>(comparator));
//}
//TreeSet<Cat> treeSet = new TreeSet<>(new Comparator2());
TreeSet<Cat> treeSet = new TreeSet<>(new Comparator1());
//用comparator3()就会报错
treeSet.add(new Cat("jerry", 20));
treeSet.add(new Cat("amy", 22));
treeSet.add(new Cat("frank", 35));
treeSet.add(new Cat("jym", 15));
for(Cat cat : treeSet){
System.out.println(cat);
}
}
}
class Comparator1 implements Comparator<Animal>{
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本