泛型中常用的通配符:
我们在定义泛型类,泛型方法,泛型接口的时候经常会碰见很多不同的通配符,比如 T,E,K,V ,?等等,这些通配符又都是什么意思呢?
- ? 表示不确定的 java 类型
- T (type) 表示具体的一个java类型
- K V (key value) 分别代表java键值中的Key Value
- E (element) 代表Element
比如在不确定泛型参数的具体类型时,可以使用?代替,比如下方的例子:
比如public void set(List> list)
在调用方法时,参数类型可以是任何参数,既可以是List也可以是List。
A extends B>是带通配符的参数化类型,它可以作为普通类型那样用于变量和方法声明等中。
用法例如下方的样式:
1. A extends B> a = ...;
2. public void foo(A extends B> a) { ... }
3. List extends Number> l;
extends Number> 表示上边界限定,泛型参数只能是Number及其子类,一旦实例化其他参数类型则会报错。
super Number> 表示下边界限定,泛型参数只能是Number和它的父类,如果传入的参数类型不是 Number 或者 Number 的子类,无法编译成功。
> 表示无界通配符,可以表示任意的参数类型。
?和 T 都表示不确定的类型,区别在于我们可以对 T 进行操作,但是对 ? 不行,比如如下这种 :
// 可以操作
T t = operate();
// 不能操作
? car = operate();
T 是一个确定的类型(确定是因为通过 T 来确保泛型参数的一致性这方面来说的),通常用于泛型类和泛型方法的定义,?是一个 不确定 的类型,通常用于泛型方法的调用代码和形参,不能用于定义类和泛型方法。
// 通过 T 来确保泛型参数类型的一致性
public void Hello(List dest, List src)
// 通配符类型是不确定的,所以这个方法不能保证两个 List 具有相同的参数类型
public void Hello(List extends Number> dest, List extends Number> src)
下面的例子由于泛型指定的数据类型是Number,但是在赋值时给出的数据类型是String,所以 发生数据类型无法相互转换的错误。改正错误的办法是赋值时使用Number的数据类型进行赋值。
import java.util.ArrayList;
import java.util.List;
class Generic {
public void genericTest(List dest, List src) {
}
}
public class GenericLearn {
public static void main(String[] args) {
List a = new ArrayList<>();
List b = new ArrayList<>();
// List a = new ArrayList();
// List b = new ArrayList();
Generic generic = new Generic();
generic.genericTest(a, b);
}
}
----------------------------------------------------
Exception in thread "main" java.lang.RuntimeException:
Uncompilable source code - Erroneous sym type: com.zhbi.source.Generic.genericTest
at com.zhbi.source.GenericLearn.main(GenericLearn.java:22)
Java Result: 1
下方为改正错误后的代码:
import java.util.ArrayList;
import java.util.List;
class Generic {
public void genericTest(List dest, List src) {
}
}
public class GenericLearn {
public static void main(String[] args) {
List a = new ArrayList<>();
List b = new ArrayList<>();
// List a = new ArrayList();
// List b = new ArrayList();
Generic generic = new Generic();
generic.genericTest(a, b);
}
}
使用 & 符号设定多重边界(Multi Bounds),指定泛型类型 T 必须是 A 和 B 的共有子类型,此时被修饰的变量就具有了所有限定的方法和属性。对于通配符?来说,因为它不是一个确定的类型,所以不能用于多重限定。
class Generic {
public void genericTest(List dest, List src) {
}
}
但是这两种数据类型必须为接口(interface)类型,比如在这里定义了两个接口A和B,同时在类中也实现了这两个接口,具体看下方的代码。
import java.util.ArrayList;
import java.util.List;
interface A {
public void a();
}
interface B {
public void b();
}
class Generic implements A, B {
public void genericTest(List dest, List src) {
}
@Override
public void a() {
}
@Override
public void b() {
}
}
public class GenericLearn {
public static void main(String[] args) {
List a = new ArrayList<>();
List b = new ArrayList<>();
Generic generic = new Generic();
generic.genericTest(a, b);
}
}
类型参数 T 只具有 一种 类型限定方式:
T extends A
但是通配符 ? 可以进行 两种限定:
? extends A
? super A
Class在实例化的时候,T 要替换成具体类。Class>它是个通配泛型,? 可以代表任何类型,所以主要用于声明时的限制情况。比如,我们可以这样做申明:
// 可以
public Class> clazz;
// 不可以,因为 T 需要指定类型
public Class clazzT;
所以当不知道定声明什么类型的 Class 的时候可以定义一 个Class>
。
public class Test3 {
public Class> clazz;
// 不会报错
public Class clazzT;
}
那如果也想 public Class
这样的话,就必须让当前的类也指定 T :
public class Test3 {
public Class> clazz;
// 不会报错
public Class clazzT;
}