一、自定义泛型类/接口
1、泛型的声明
interface List<T> 和 class GenTest<K,V>其中, T,K,V不代表值,而是表示类型。 这里使用任意字母都可以。
常用T表示,是Type的缩写。
2、泛型的实例化
一定要在类名后面指定类型参数的值(类型)。如:
1 List<String> strList = new ArrayList<String>();
2 Iterator<Customer> iterator = customers.iterator();
T只能是类,不能用基本数据类型填充。但可以使用包装类填充。
把一个集合中的内容限制为一个特定的数据类型,这就是generics背后的核心思想。
注意:使用泛型的主要优点是能够在编译时而不是在运行时检测错误。
3、自定义泛型类/接口的注意事项
(1)泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:<E1,E2,E3>;
(2)泛型类的构造器如下: public GenericClass(){}。而下面是错误的: public GenericClass<E>(){};
(3)实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。
(4)泛型不同的引用不能相互赋值。
尽管在编译时ArrayList<String>和ArrayList<Integer>是两种类型,但是,在运行时只有一个ArrayList被加载到JVM中。
(5)泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价于Object。
经验: 泛型要使用一路都用。要不用,一路都不要用。
(6)如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象
(7)jdk1.7,泛型的简化操作: ArrayList<Fruit> flist = new ArrayList<>();
(8)泛型的指定中不能使用基本数据类型,可以使用包装类替换。
(9)在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态属性的类型、非静态方法的参数类型、非静态方法的返回值类型。但在静态方法
中不能使用类的泛型。
(10) 异常类不能是泛型的
(11)不能使用new E[]。但是可以: E[] elements = (E[])new Object[capacity];
参考: ArrayList源码中声明: Object[] elementData, 而非泛型参数类型数组。
(12)父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型:
子类不保留父类的泛型:按需实现
没有类型 擦除
具体类型
子类保留父类的泛型:泛型子类
全部保留
部分保留
结论:子类必须是“富二代”,子类除了指定或保留父类的泛型,还可以增加自己的泛型
4、自定义泛型案例
(1)泛型类的构造器声明
1 public class Order<T> {
2
3 String orderName;
4 int orderId;
5
6 //类的内部结构就可以使用类的泛型
7
8 T orderT;
9
10 public Order(String orderName,int orderId,T orderT){
11 this.orderName = orderName;
12 this.orderId = orderId;
13 this.orderT = orderT;
14 }
15
16 }
(2)泛型不同的引用不能相互赋值
1 ArrayList<String> list1 = null;
2 ArrayList<Integer> list2 = new ArrayList<Integer>();
3 //泛型不同的引用不能相互赋值。
4 // list1 = list2; 编译不通过
(3)泛型不指定,将被擦除,泛型对应的类型按照 Object 处理,但不等价于 Object。
1 @Test
2 public void test1(){
3 //如果定义了泛型类,实例化没有指明类的泛型,则认为此泛型类型为Object类型
4 //要求:如果大家定义了类是带泛型的,建议在实例化时要指明类的泛型。
5 Order order = new Order();
6 order.setOrderT(123);
7 order.setOrderT("ABC");
8
9 //建议:实例化时指明类的泛型
10 Order<String> order1 = new Order<String>("orderAA",1001,"order:AA");
11
12 order1.setOrderT("AA:hello");
13
14 }
1 class GenericTest {
2 public static void main(String[] args) {
3 // 1、使用时:类似于Object,不等同于Object
4 ArrayList list = new ArrayList();
5 // list.add(new Date());//有风险
6 list.add("hello");
7 test(list);// 泛型擦除,编译不会类型检查
8 // ArrayList<Object> list2 = new ArrayList<Object>();
9 // test(list2);//一旦指定Object,编译会类型检查,必须按照Object处理
10 }
11
12 public static void test(ArrayList<String> list) {
13 String str = "";
14 for (String s : list) {
15 str += s + ",";
16 }
17 System.out.println("元素:" + str);
18 }
19 }
(4)静态方法不能使用类的泛型。
1 // public static void show(T orderT){
2 // System.out.println(orderT);
3 // }
因为静态方法是加载类时加载的,而类的泛型是实例化时才能确定的,晚于静态方法。
(5)异常类不能声明为泛型类。不能在 try-catch 中使用泛型定义
1 public class MyException<T> extends Exception{} //编译错误
2
3 public void show(){
4 //编译不通过
5 // try{
6 //
7 //
8 // }catch(MyException<T> ex){
9 //
10 // }
11
12 }
(6)不能使用 new E[]。但是可以:E[] elements = (E[])new Object[capacity];
1 public Order(){
2 //编译不通过
3 //T[] arr = new T[10];
4 //编译通过
5 T[] arr = (T[]) new Object[10];
6 }
(7)子类可以选择保留泛型也可以选择指定泛型类型,还可以增加自己的泛型。
1 class Father<T1, T2> {}
2
3 // 子类不保留父类的泛型
4 // 1)没有类型 擦除
5 class Son1 extends Father {// 等价于class Son extends Father<Object,Object>{}
6 // 2)具体类型
7 class Son2 extends Father<Integer, String> {}
8
9 // 子类保留父类的泛型
10 // 1)全部保留
11 class Son3<T1, T2> extends Father<T1, T2> {}
12 // 2)部分保留
13 class Son4<T2> extends Father<Integer, T2> {}
1 class Father<T1, T2> {}
2
3 // 子类不保留父类的泛型
4 // 1)没有类型 擦除
5 class Son<A, B> extends Father{//等价于class Son extends Father<Object,Object>{}
6 // 2)具体类型
7 class Son2<A, B> extends Father<Integer, String> {}
8
9 // 子类保留父类的泛型
10 // 1)全部保留
11 class Son3<T1, T2, A, B> extends Father<T1, T2> {}
12 // 2)部分保留
13 class Son4<T2, A, B> extends Father<Integer, T2> {}
(8)自定义泛型类
1 class Person<T> {
2 // 使用T类型定义变量
3 private T info;
4
5 // 使用T类型定义一般方法
6 public T getInfo() {
7 return info;
8 }
9
10 public void setInfo(T info) {
11 this.info = info;
12 }
13
14 // 使用T类型定义构造器
15 public Person() {
16 }
17
18 public Person(T info) {
19 this.info = info;
20 }
21 }
二、自定义泛型方法
1、概述
方法,也可以被泛型化,不管此时定义在其中的类是不是泛型类。
在泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型。
泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化类时确定。
2、泛型方法格式
[访问权限] <泛型> 返回类型 方法名([泛型标识 参数名称]) 抛出的异常
3、案例一
1 public class DAO {
2 public <E> E get(int id, E e) {
3 E result = null;
4 return result;
5 }
6 }
4、案例二
1 public static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
2 for (T o : a) {
3 c.add(o);
4 }
5 }
6 public static void main(String[] args) {
7 Object[] ao = new Object[100];
8 Collection<Object> co = new ArrayList<Object>();
9 fromArrayToCollection(ao, co);
10
11
12 String[] sa = new String[20];
13 Collection<String> cs = new ArrayList<>();
14 fromArrayToCollection(sa, cs);
15
16
17 Collection<Double> cd = new ArrayList<>();
18 // 下面代码中T是Double类,但sa是String类型,编译错误。
19 //fromArrayToCollection(sa, cd);
20
21
22 // 下面代码中T是Object类型, sa是String类型,可以赋值成功。
23 fromArrayToCollection(sa, co);
24 }
5、案例三
1 class Creature{}
2 class Person extends Creature{}
3 class Man extends Person{}
4 class PersonTest {
5 public static <T extends Person> void test(T t){
6 System.out.println(t);
7 }
8 public static void main(String[] args) {
9 test(new Person());
10 test(new Man());
11 //The method test(T) in the type PersonTest is not
12 //applicable for the arguments (Creature)
13 test(new Creature()); //编译报错
14 }
15 }
6、案例四
1 public static <E> List<E> copyFromArrayToList(E[] arr){
2
3 ArrayList<E> list = new ArrayList<>();
4
5 for(E e : arr){
6 list.add(e);
7 }
8 return list;
9
10 }