- 适用于多种数据类型执行相同的代码。
- 泛型中的类型在使用时指定,不需要强制类型转换(出现异常 java.lang.ClassCastException)。
泛型:参数化类型,将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
//泛型类
public class NormalGeneric<T> {
private T data;
public NormalGeneric(T data) {
this.data = data;
}
}
//泛型接口
public interface IGenerator<T> {
T getData();
}
//1.实现泛型接口方式
public class ImplGenerator1<T> implements IGenerator<T>
//2.实现泛型接口方式
public class ImplGenerator2 implements IGenerator<String>
可以在任何地方定义,普通类、泛型类等。
public class GeneratorMethod {
public <T> T getMethod(T... a) { //使用 <T>
return a[a.length / 2];
}
public static void main(String[] args) {
GeneratorMethod generatorMethod = new GeneratorMethod();
String s = generatorMethod.getMethod("Java", "C++");
System.out.println(s);
}
}
public class NoGeneratorMethod<T> {
private T key;
public NoGeneratorMethod(T key){
this.key = key;
}
public T getKey() { //注意:不是泛型方法
return key;
}
}
对类型变量进行约束,,可以在泛型类、泛型接口、泛型方法上世使用。
public <T extends Comparable> T max(T a, T b) {
return a.compareTo(b) > 0 ? a : b;
}
//extends左右都允许有多个,如 T,V extends Comparable & Serializable
//但是只允许有一个类,且必须在列表第一个位置
public <T extends Comparable & Serializable> T min(T a, T b) {
return a.compareTo(b) > 0 ? b : a;
}
//不能使用类型变量
public static T instance;
//基本数据类型不支持
NormalGeneric<int> a = new NormalGeneric<>();//出错
//创建数组不支持
NormalGeneric<Integer>[] a = new NormalGeneric<>[9];//出错
//不能实例化类型变量
this.data = new T();
//不能 extends Exception、Throwable,不能捕获泛型类实例
public static class MyException<T> extends Exception {
public <T extends Throwable> void doWork(T t) {
try {
} catch (T e) {
}
}
public <T extends Throwable> void doWork1(T t) throws T{
try {
} catch (Throwable e) {
throw e;//可以抛出泛型异常
}
}
}
public class Fruit {}
public class Apple extends Fruit {}
public class Banana extends Fruit {}
public class GreenBanana extends Banana {}
public class GenericType<T> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
表示类型的上界,类型参数是 X 的子类。
public static void main(String[] args) {
GenericType<Fruit> a = new GenericType<>();
GenericType<? extends Fruit> b = new GenericType<>();
GenericType<Apple> c = new GenericType<>();
a = c; //出错
b = c; //可以 <? extends Fruit> 表示上界是 Fruit ,子类当然可以。
Apple apple = new Apple();
Banana banana = new Banana();
b.setData(apple);//出错 上限:set 不可
b.setData(banana);//出错
Fruit fruit = b.getData();//可以,上限:get 可行
}
表示类型的下界,类型参数是 X 的超类
public static void main(String[] args) {
GenericType<? super Banana> a = new GenericType<>();
GenericType<GreenBanana> b = new GenericType<>();
GenericType<Fruit> c = new GenericType<>();
a = b;//出错
a = c;//可以 <? super Banana> 表示下界是 Banana ,他的超类当然可以
Banana banana = new Banana();
GreenBanana greenBanana = new GreenBanana();
Fruit fruit = new Fruit();
a.setData(banana);//可以
a.setData(greenBanana);//可以
a.setData(fruit);//出错 <? super Banana> 表示下界是 Banana,Fruit 超了,强记
Object data = a.getData();//唯一取值是 Object
}
表示对类型没有什么限制,可以把 ?看成所有类型的父类,如Pair< ?>;
比如:
ArrayList al=new ArrayList(); 指定集合元素只能是T类型
ArrayList al=new ArrayList();集合元素可以是任意类型,这种没有意义,一般是方法中,只是为了说明用法。
在使用上:
? getFirst() : 返回值只能赋给 Object,;
void setFirst(?) : setFirst 方法不能被调用, 甚至不能用 Object 调用;
类型擦除,Java 泛型是伪泛型,仅仅是对方法的 Code 属性中的字节码进行擦除,实际上元数据中还是保留了泛型信息,能通过反射手段取得参数化类型,使用 Signature 存储一个方法在字节码层面的特征签名(泛型类型)。