#来自ゾフィー(佐菲)
1 泛型的作用
- 适用于多种数据类型执行相同的代码。
- 泛型中的类型在使用时指定,不需要强制类型转换(出现异常 java.lang.ClassCastException)。
2 泛型类和泛型接口
泛型:参数化类型,将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
//泛型类 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>
3 泛型方法
可以在任何地方定义,普通类、泛型类等。
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; } }
4 限定类型变量
对类型变量进行约束,,可以在泛型类、泛型接口、泛型方法上世使用。
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; }
5 注意
//不能使用类型变量 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;//可以抛出泛型异常 } } }
6 通配符类型
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; } }
6.1 ? extends X
表示类型的上界,类型参数是 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 可行 }
6.2 ? super X
表示类型的下界,类型参数是 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 }
6.3 无限定的通配符 ?
表示对类型没有什么限制,可以把 ?看成所有类型的父类,如Pair< ?>;
比如:
ArrayList al=new ArrayList(); 指定集合元素只能是T类型
ArrayList al=new ArrayList();集合元素可以是任意类型,这种没有意义,一般是方法中,只是为了说明用法。
在使用上:
? getFirst() : 返回值只能赋给 Object,;
void setFirst(?) : setFirst 方法不能被调用, 甚至不能用 Object 调用;
7 虚拟机实现泛型
类型擦除,Java 泛型是伪泛型,仅仅是对方法的 Code 属性中的字节码进行擦除,实际上元数据中还是保留了泛型信息,能通过反射手段取得参数化类型,使用 Signature 存储一个方法在字节码层面的特征签名(泛型类型)。