概述
1、通配符类型(?)
通配符类型可以理解为一种泛型调用时传递的一种特殊数据类型,表示参数允许在某个范围内变化。通配符类型有三种,分别是?,? extends,? super。
通配符表示一种未知类型,并且对这种未知类型存在约束关系.
<?>
?的默认是实现是? extends Object,表示?是继承Object的任意类型。
<? extends T> 上限通配
这里?表示一个未知的类,而T是一个具体的类,在实际使用的时候T需要替换成一个具体的类,表示实例化的时候泛型参数要是T或T的子类。
例如:
//定义方法
public static void function1(List<? extends Number> list){
System.out.println(list.get(0).toString());
}
//使用方法
List<Integer> list1 = new ArrayList<>();
list.add(1);
List<Number> list2 = new ArrayList<>();
list2.add(2);
Demo.function1(list);
Demo.function1(list2);
<? super T> 下限通配
这里?表示一个未知的类,而T是一个具体的类,在实际使用的时候T需要替换成一个具体的类,表示实例化的时候泛型参数要是T或是T的父类。
例如:
//定义方法
public static void function2(List<? super Integer> list){
System.out.println(list.get(0).toString());
}
//使用方法
List<Integer> list = new ArrayList<>();
list.add(1);
List<Number> list2 = new ArrayList<>();
list2.add(2);
Demo.function2(list);
Demo.function2(list2);
PECS(producer-extends,consumer-super)
Effective Java中提出的一种概念;生成者使用<? extends T>,消费者使用<? super T>。
下面例子中,T为Number类型,这里的src里面的对象都是Number的子类,而接收数据的dest定义的泛型都是Number的父类,所以src中生成的数据存储到dest不会出现类型异常。
例如:
/**
* 生成者使用<? extends T>,消费者使用<? super T>
* @param src
生产者
* @param dest 消费者
* @param <T>
*/
public static <T> void copy(List<? extends T> src, List<? super T> dest) {
for (int i = 0; i < src.size(); i++) {
dest.set(i, src.get(i));
}
}
List<? extends Number> src = new ArrayList<>();
List<? super Number> dest = new ArrayList<>();
Demo.copy(src, dest);
2、E、T、K、V、N
本质上以下字母都可以相互替换,但我们按照下面定义约定俗成的含义来使用。
E - Element (在集合中使用,因为集合中存放的是元素)
T - Type(Java 类)
K - Key(键)
V - Value(值)
N - Number(数值类型)
? - 表示不确定的java类型
S、U、V - 2nd、3rd、4th types
在定义泛型时,每个字母都限定代表同一个类型。比如使用T时,会限定多处使用T的指定类型必须要相同。
在下面例子中,src2和dest2的泛型类型必须相同,否则编译无法通过。
例如:
//定义T参数的方法
public static <T> void copy2(List<T> src, List<T> dest) {
System.out.println("doSomething..");
}
//正确使用
List<Number> src2 = new ArrayList<>();
List<Number> dest2 = new ArrayList<>();
Demo.copy2(src2, dest2);
//错误使用
List<Number> src2 = new ArrayList<>();
List<Integer> dest2 = new ArrayList<>();
Demo.copy2(src2, dest2);
3、? 与 T 的差别
? 表示一个未知类型, T 是表示一个确定的类型。 因此,无法使用 ? 像 T 声明变量和使用变量。
例如:
// 正确定义
static <T> void test1(List<T> list) {
T t = list.get(0);
t.toString();
}
// 错误定义
static void test2(List<?> list){
? t = list.get(0);
t.toString();
}
4、附代码
import java.util.ArrayList;
import java.util.List;
public class Client {
public static void main(String[] args) {
//通配符的上、下限使用
List<Integer> list1 = new ArrayList<>();
list1.add(1);
List<Number> list2 = new ArrayList<>();
list2.add(2);
Demo.function1(list1);
Demo.function2(list1);
Demo.function1(list2);
Demo.function2(list2);
//PECS
List<? extends Number> src = new ArrayList<>();
List<? super Number> dest = new ArrayList<>();
Demo.copy(src, dest);
//T的限定类型 正确使用
List<Number> src2 = new ArrayList<>();
List<Number> dest2 = new ArrayList<>();
Demo.copy2(src2, dest2);
//T的限定类型 错误使用,会出现编译错误
List<Number> src2 = new ArrayList<>();
List<Integer> dest2 = new ArrayList<>();
Demo.copy2(src2, dest2);
}
}
import java.util.List;
public class Demo {
public static void function1(List<? extends Number> list) {
System.out.println(list.get(0).toString());
}
public static void function2(List<? super Integer> list) {
System.out.println(list.get(0).toString());
}
/**
* 生成者使用<? extends T>,消费者使用<? super T>
* @param src
生产者
* @param dest 消费者
* @param <T>
*/
public static <T> void copy(List<? extends T> src, List<? super T> dest) {
for (int i = 0; i < src.size(); i++) {
dest.set(i, src.get(i));
}
}
public static <T> void copy2(List<T> src, List<T> dest) {
System.out.println("doSomething..");
}
}
最后
以上就是美满魔镜为你收集整理的Java通配符和类型参数的使用(?和T的区别)1、通配符类型(?)2、E、T、K、V、N3、? 与 T 的差别4、附代码的全部内容,希望文章能够帮你解决Java通配符和类型参数的使用(?和T的区别)1、通配符类型(?)2、E、T、K、V、N3、? 与 T 的差别4、附代码所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复