一、自定义泛型类/接口

  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 }

 

posted on 2021-05-23 13:37  格物致知_Tony  阅读(363)  评论(0编辑  收藏  举报