zoukankan      html  css  js  c++  java
  • Java 泛型(二):自定义泛型结构

    一、自定义泛型类/接口

      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 }
  • 相关阅读:
    logging模板日志格式
    MariaDB修改默认字符集
    Django之表单验证
    Django之定制属于自己的admin
    sympy-高数可以这么学
    matplotlib01
    mysql---- 用户权限管理
    django----JSONP知识回顾
    django----文件上传
    数据库结构备份
  • 原文地址:https://www.cnblogs.com/niujifei/p/14801020.html
Copyright © 2011-2022 走看看