写代码时,看到别人用List、Map<K, V>,心里想:这T、E、K、V到底啥意思?能不能换成A、B、C??又是啥?问又不太好意思问…… 咱们直接进入主题。

泛型是啥?

泛型: “类型占位符”。 比如你写个工具类,想让它既能处理String,也能处理Integer,咋办? 你总不能写两个方法吧?太麻烦! 这时候,泛型就来了。你先用个“代号”代替具体类型,等用的时候再告诉它“哦,这次是String”。

 这些字母就是“代号”的约定写法。不是语法规定,是大家都用习惯了的规矩。 
 你非要写List<B>,语法也是OK的。但别人看了可能会懵。

那T、E、K、V、?是啥?有啥区别

所以,这几个代号可以看做是这几个意思:

T → Type(类型)
最最常见的,代表“任意类型”。 使用场景:写一个通用方法或类,不知道具体类型。

public class Box<T> {
	private T content;
	
	public void setContent(T t) {
		this.content = t;
	}
	public T getContent() {
		return content;
	}
}

用的时候:
看具体实例化的时候给的类型

Box<String> stringBox = new Box<>();
stringBox.setContent("你好");
Box<Integer> intBox = new Box<>();
intBox.setContent(100);

T就是个“占位符”,传String它就是String;传Integer它就是Integer。

E → Element(元素)
一般用在集合里,表示“集合中的元素类型”。 使用场景:List、Set这些容器。

public interface List<E> {
	boolean add(E e);
	E get(int index);
}

JDK源码就是这么写的。E = Element,一看就知道是“里面装的东西”。

List<String> list = new ArrayList<>();
// 这里的String,就是E

所以,E和T没啥本质区别,但语义不同:E强调的是“这是集合里的元素”。

K和V = Key和Value
这个最简单,专用于Map。 使用场景:Map类、方法。

public interface Map<K, V> {
	V put(K key, V value);
	V get(Object key);
}
Map<String, Integer> map = new HashMap<>();
map.put("年龄", 18);
// K是String,V是Integer

只要看到Map,基本就是K和V。

? → 通配符(问号,就是“不知道”)
使用场景:你不想限制类型,或者类型不重要。

比如,你写个方法,只想打印List的大小,不管里面是String还是Integer。

public void printSize(List<?> list) {
    System.out.println("大小:" + list.size());
}

这里的 ? 表示任何类型都行(除了null),因为类型不确定。 但可以读,比如list.get(0),返回的是Object。
再举个例子:

List<?> list1 = new ArrayList<String>();
List<?> list2 = new ArrayList<Integer>();

还有一个变种:<? extends T>和<? super T>

<? extends Animal>:只要是Animal的子类都可以
<? super Dog>:只要是Dog的父类都可以

但日常用得少, ?就是“我不关心你啥类型”。

总结

T:Type,通用类型,最常用
E:Element,集合里的元素
K:Key,Map的键
V:Value,Map的值
?:问号,类型不确定

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐