概念
泛型是JDK5引入的一个特性,在编译时进行类型安全检测,本质是类型参数化,引入的泛型的意义在于:
- 实现代码复用。
- 类型安全检测,对类型进行约束,在使用过程中不需要进行类型强转。
泛型类型
泛型类型分为三类:泛型类、泛型接口、泛型方法。
- 泛型类
public class GenericClassTest {
/**
* 泛型类
* @param <T>
*/
public static class Result<T> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
public static void main(String[] args) {
Result<String> result = new Result<>();
result.setData("这是一个泛型类:参数类型是String");
System.out.println(result.getData());
}
}
- 泛型接口
public class GenericInterfaceTest {
/**
* 泛型接口
* @param <I> 输入类型
* @param <R> 结果类型
*/
public interface ITransform<I, R>{
/**
* 输入指定的类型
* @param input 输入类型
* @return 返回结果类型
*/
R getResult(I input);
}
static class Transform implements ITransform<Integer, String> {
@Override
public String getResult(Integer input) {
return "Input为输入的类型,Result为输出的类型,输出"+input;
}
}
public static void main(String[] args) {
ITransform<Integer, String> transform = new Transform();
System.out.println(transform.getResult(3));
}
}
- 泛型方法
public class GenericMethodTest {
static class Base{
private String value;
public Base() {
this.value = "初始化";
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
/**
* 泛型方法
*
* @param t 参数
* @param <T> 标记入参的类型
* @return 返回E类型
*/
public static <T> T newInstance(Class<T> t) throws Exception {
// 返回一个对象实例
return t.newInstance();
}
public static <E> E[] newArray(E... e) {
// 一个生成泛型数组的取巧方法
return e;
}
public static <E> E[] generateArray(Class<E> eClass, int size) {
// 泛型数据不能直接创建
// E[] arrays = new E[size];
// 合理使用
return (E[]) Array.newInstance(eClass, size);
}
public static void main(String[] args) throws Exception {
Base base = newInstance(Base.class);
System.out.println(base.getValue());
Integer[] array = newArray(1,2,4);
System.out.println(Arrays.toString(array));
String[] strings = generateArray(String.class, 10);
System.out.println(strings.length);
strings[0] = "数组";
System.out.println(Arrays.toString(strings));
}
}
常用通配符
泛型通配符的名称都是用来表示一个Java类型,没什么太大的区别,通常用一个大写字母来表示。常用的字母如下:
- T(type) 表示一个Java类型如
Consumer<T> - U、V 位于T后面,可认为是第二个类型,第三个类型,如
BiPredicate<T, U> - R(Result) 表示一个结果类型,如
BiFunction<T, U, R> - E(Element) 在集合中使用,如
ArrayList<E> - K V(Key Value) 表示一个键值对,如
HashMap<K,V> - S(Stream) 表示一个流,如
BaseStream<T, S> - N(Number) 数值类型
- ? 表示一个未知类型
类型擦除
类型擦除(Type Erasure)是Java的一种编译时机制,用于实现泛型的类型安全,并在运行时擦除泛型的具体类型信息(运行时具体类型不可用),即泛型类型参数被替换为具体类型的第一个上界类型或者
Object类型,主要目的是为了保持与Java的早期版本代码的兼容性。
public class GenericTypeErasureTest {
static class TypeErasure<T,U>{
// 类型擦除 参数为(Object value)
public void setValue(T value) {
System.out.println(value);
}
// 类型擦除 参数为(Object value)
public void setValue(U value) {
System.out.println(value);
}
}
static class TypeErasurePass<T extends Number,U>{
// 类型擦除,参数为 (Number value)
public void setValue(T value) {
System.out.println(value);
}
// 类型擦除,参数为 (Object value)
public void setValue(U value) {
System.out.println(value);
}
}
}
类型限定
类型限定是为泛型的类型参数确定边界,对该泛型的使用范围进行一个约束。
<T extend Animal>用于修饰类、接口、方法? extends Animal有外围类才能使用,如List<? extends Animal>? super Cat有外围类才能使用,如List<? super Feline>
一个类型变量或者通配符可以有多个限定,使用&分隔类型变量,但是只能有一个限定类(class)其他为接口(interface),如
class MultiClass<T extends Number & Comparable<T> & Serializable> {
private T data;
}
PECS原则: producer extends consumer super
《Effictive Java》描述中,为了获取最大的灵活性,要在生产者和消费者的输入参数上添加边界,使得生产有上限,消费有下线,也就是PECS原则。
public class GenericQualifyTest {
static class Animal {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void description() {
System.out.println("动物描述");
}
}
static class Feline extends Animal {
public Feline() {
super.setName("猫科动物");
}
@Override
public void description() {
System.out.println("Feline is Cat upper bound");
}
}
static class Cat extends Feline {
public Cat() {
super.setName("小猫咪");
}
@Override
public void description() {
System.out.println("猫会喵喵叫");
}
}
static class Primate extends Animal {
public Primate() {
super.setName("灵长类动物");
}
@Override
public void description() {
System.out.println("Primate is Monkey upper bound");
}
}
/**
* 限定上界类
*
* @param <T> Animal类及其子类
*/
static class UpperClass<T extends Animal> {
public T data;
public UpperClass(T data) {
this.data = data;
}
public UpperClass() {
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
static <T extends Feline> T getFeline(Class<T> tClass)
throws InstantiationException, IllegalAccessException {
return tClass.newInstance();
}
/**
* 测试类型上限
*
* @throws Exception
*/
static void testTypeUpper() throws Exception {
// getFeline(Animal.class); // ERROR 限定类型
Feline feline = getFeline(Feline.class);
Cat cat = getFeline(Cat.class);
feline.description();
cat.description();
// UpperClass<Integer> upperClass = new UpperClass<Integer>(); // ERROR 限定了类型
// UpperClass<Cat> upperClass = new UpperClass<>(); // 使用该行 upperClass.setData(feline); 无法注入
UpperClass<Animal> upperClass = new UpperClass<>();
upperClass.setData(cat);
upperClass.setData(feline);
}
static void testConsumer() {
System.out.println("=============测试消费者==============");
List<? super Feline> felines = new ArrayList<>();
felines.add(new Cat());
Object object = felines.get(0);
((Cat) object).description();
List<UpperClass<? super Feline>> upperClassList = new ArrayList<>();
UpperClass<Animal> animalUpperClass = new UpperClass<>();
Animal animal = new Animal();
animalUpperClass.setData(animal);
Cat cat = new Cat();
UpperClass<Cat> catUpperClass = new UpperClass<>();
catUpperClass.setData(cat);
UpperClass<Primate> primateUpperClass = new UpperClass<>();
primateUpperClass.setData(new Primate());
UpperClass<Feline> felineUpperClass = new UpperClass<>();
felineUpperClass.setData(new Feline());
upperClassList.add(felineUpperClass);
upperClassList.add(new UpperClass<>(new Primate())); // 这种实例化似乎跳过了编译检查
// upperClassList.add(catUpperClass); // ERROR 确定下界,从Feline开始
// upperClassList.add(primateUpperClass);
UpperClass<? super Feline> upperClass = upperClassList.get(0);
Animal data = upperClass.getData(); // 显示上界类型
data.description();
List<? super UpperClass<? super Feline>> superSuperList = new ArrayList<>();
superSuperList.add(animalUpperClass);
Object superSuperObject = superSuperList.get(0);
((UpperClass<Animal>) superSuperObject).getData().description();
// ERROR UpperClass<? super Feline> 确定UpperClass类型参数Feline为下界
// ? super UpperClass<? super Feline> 是确定UpperClass为下界,所以就是Object
// superSuperList.add(catUpperClass);
// superSuperList.add(primateUpperClass);
List<? super UpperClass<? extends Feline>> superExtendsList = new ArrayList<>();
superExtendsList.add(catUpperClass);
Object superExtendsObject = superExtendsList.get(0);
((UpperClass<Cat>) superExtendsObject).getData().description();
// ERROR UpperClass<? extends Feline> 确定UpperClass类型参数Feline为上界
// <? super UpperClass<? extends Feline> 是确定UpperClass为下界,所以就是Object
// superExtendsList.add(animalUpperClass);
// superExtendsList.add(primateUpperClass);
}
static void testProducer() {
System.out.println("===========测试生产者==============");
UpperClass<? extends Feline> felineUpperClass = new UpperClass<>();
// felineUpperClass.setData(new Feline());// 向下转型,不能确定类型
// felineUpperClass.setData(new Primate());
Feline data = felineUpperClass.getData();
System.out.println(data); // 空数据
List<UpperClass<? extends Feline>> upperClasses = new ArrayList<>();
upperClasses.add(new UpperClass<>(new Cat()));
// upperClasses.add(new UpperClass<>(new Animal()); // 确定上界,由Feline开始
// upperClasses.add(new UpperClass<>(new Primate()));
for (UpperClass<? extends Feline> upperClass : upperClasses) {
upperClass.getData().description();
}
List<? extends UpperClass<? extends Feline>> extendsExtendsList
= new ArrayList<UpperClass<? extends Feline>>() {{
UpperClass<Cat> upperClass = new UpperClass<>();
upperClass.setData(new Cat());
this.add(upperClass);
// this.add(new UpperClass<>(new Primate())); // 限定类型
}};
for (UpperClass<? extends Animal> upperClass : extendsExtendsList) {
upperClass.getData().description();
}
// 向下转型,无法确认类型
// extendsExtendsList.add(new UpperClass<>(new Cat()))
// extendsExtendsList.add(new UpperClass<>(new Primate()));
List<? extends UpperClass<? super Feline>> extendsSuperList
= new ArrayList<UpperClass<? super Feline>>() {{
UpperClass<Animal> animalUpperClass = new UpperClass<>();
animalUpperClass.setData(new Animal());
UpperClass<Cat> catUpperClass = new UpperClass<>();
catUpperClass.setData(new Cat());
UpperClass<Primate> primateUpperClass = new UpperClass<>();
primateUpperClass.setData(new Primate());
UpperClass<Feline> felineUpperClass = new UpperClass<>();
felineUpperClass.setData(new Feline());
this.add(animalUpperClass);
this.add(felineUpperClass);
this.add(new UpperClass<>(new Primate())); // 这种实例化似乎跳过了编译检查
// this.add(catUpperClass); // ERROR
// this.add(primateUpperClass); // ERROR
}};
for (UpperClass<? super Feline> upperClass : extendsSuperList) {
Animal animal = upperClass.getData();
animal.description();
}
// 向下转型,无法确定类型
// extendsSuperList.add(new UpperClass<>(new Cat()));
}
public static void main(String[] args) throws Exception {
testTypeUpper();
testConsumer();
testProducer();
}
}
泛型的约束和局限性
- 不能用基本类型实例化类型参数
Generic<int[]> generic = new Generic<>(),类型擦除 - 不能创建参数化类型数组
Generic<String>[] generics = new Generic<String>[10],但是Generic<String>[] generics = new Generic[10]是合法的 - 运行时类型查询只适用原始类型,
Pair<String>只能 查询到Pair,得不到<>里的类型 - 不能使用
new实例化类型变量T t= new T() - 不能直接构造泛型数组
T[] ts = new T[10] - 泛型类的静态上下文中类型变量无效
class Generic<T> {private static T staticT} - 不能抛出或捕获泛型类实例,扩展Throwable都是不合法的(类型擦除),但是在异常规范使用类型变量是被允许的,即
<T extends Throwable> void handle(T t) throws T
public class GenericRestrainTest {
static class Generic<T> {
// 静态变量没有实例化,无法知道类型
private static T staticT;
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
static <T> void newInstance() {
T t = new T(); // 不能使用new创建实例
T[] ts = new T[10]; // 不能构建泛型数组
}
public static void main(String[] args) {
Generic<int[]> generic = new Generic<>();
int[] a = new int[5];
generic.setData(a);
System.out.println(Arrays.toString(generic.getData()));
// Generic<int> generic1 = new Generic<int>(); // ERROR 类型参数不能使用基本类型
Generic<String>[] genericsMatchs = new Generic<String>[10]; // 编译出错
// Generic<String>[] generics = new Generic<>[10]; // 运行出错
Generic<String>[] generics = new Generic[10]; // OK 但是会有警告
Generic<String> stringGeneric = new Generic<>();
stringGeneric.setData("generic");
Generic<Integer> integerGeneric = new Generic<>();
integerGeneric.setData(10);
generics[0] = stringGeneric;
// generics[1] = integerGeneric; // 限定了String
System.out.println(generics[0].getData());
Generic<?>[] generics1 = new Generic[10];
generics1[0] = stringGeneric;
generics1[2] = integerGeneric;
System.out.println(generics1[0].getData());
Generic<?>[] generics2 = new Generic<?>[10];
Generic<String>[] generics3 = new Generic<?>[10]; // 编译出错
Generic<String>[] generics4 = (Generic<String>[]) new Generic<?>[10]; // 强转
}
public static <T extends Throwable> void handle(T t) throws T {
try {
} catch (Throwable actuallyCause) {
t.initCause(actuallyCause);
throw t;
}
// 不能在catch中使用泛型变量
catch (T throwable) {}
}
}
参考文档
《Java核心技术卷 Ⅰ》