3、自定义泛型

自定义泛型:

泛型的声明:
 interface List<T> 和 class GenTest<K,V> 
 其中,T、K、V不代表值,而是表示类型。这里使用任意字母都可以。常用T表示,是Type的缩写。
 
泛型的实例化: 
 一定要在类名后面指定类型参数的值(类型)。如: 
  List<String> strList = new ArrayList<String>(); 
  Iterator<Customer> iterator = customers.iterator();
 T只能是类,不能用基本数据类型填充。但可以使用包装类填充。
 把一个集合中的内容限制为一个特定的数据类型,这就是泛型背后的核心思想。

注意点:
1、泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:<E1,E2,E3> 
2、泛型类的构造器如下:public GenericClass(){}。而下面是错误的:public GenericClass<E>(){} 
3、实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。 
4、泛型不同的引用不能相互赋值。 
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、父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型:
子类不保留父类的泛型:按需实现 
 没有类型 擦除 
 具体类型
子类保留父类的泛型:泛型子类 
 全部保留 
 部分保留 
结论:子类必须是 "富二代",子类除了指定或保留父类的泛型,还可以增加自己的泛型。


T、E、K、V:
K、V:一般就是结合使用,键值对;
自定义的时候,使用T或E就行;


自定义泛型类:

自定义泛型接口:

自定义泛型方法:
 方法,也可以被泛型化;不管此时定义在其中的类是不是泛型类,方法是否可以泛型和方法所处的类是否使用泛型没关系。在泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型。
 泛型方法的格式:[访问权限] <泛型> 返回类型 方法名([泛型标识 参数名称]) 抛出的异常;
 泛型方法声明泛型时也可以指定上限;
 
实例1:自定义泛型类
// 当一个类中的某些内部结构(属性的类型、方法的入参类型、方法的返回值类型等)不能确定时,此时不确定的内部结构就可以使用泛型
public class Order<T> {

    // 下面这两个属性类型确定
    String orderName;
    int orderId;

    // 下面这个属性的类型不确定,此时就可以使用泛型
    T orderT;

    public Order(String orderName,int orderId,T orderT){
        this.orderName = orderName;
        this.orderId = orderId;
        this.orderT = orderT;
    }

    public T getOrderT(){
        return orderT;
    }

    public void setOrderT(T orderT){
        this.orderT = orderT;
    }

    @Override
    public String toString() {
        return "Order{" +
                "orderName='" + orderName + '\'' +
                ", orderId=" + orderId +
                ", orderT=" + orderT +
                '}';
    }
}

==========================================================================
    
public class GenericTest {

    @Test
    public void test1() {
        // 如果定义了泛型类,实例化没有指明类的泛型,则认为此泛型类型为 Object 类型
        // 要求:如果大家定义了类是带泛型的,建议在实例化时要指明类的泛型
        Order order = new Order();
        order.setOrderT(123);
        order.setOrderT("ABC");

        // 建议:实例化时指明类的泛型
        Order<String> order1 = new Order<String>("orderAA",1001,"order:AA");

        order1.setOrderT("AA:hello");
        // 下面就编译报错了
        // order1.setOrderT(123);
    }  
}
实例2:
// SubOrder 不是泛型类
public class SubOrder extends Order<Integer> {

}

=================================================================================
    
public class GenericTest {

    @Test
    public void test2() {
        SubOrder sub1 = new SubOrder();
        // 由于子类在继承带泛型的父类时,指明了泛型类型。则实例化子类对象时,不再需要指明泛型。
        sub1.setOrderT(1122);
        // 下面编译报错
        // sub1.setOrderT("1122");
    } 
}
实例3:
// SubOrder1<T> 仍然是泛型类
// Order 后面如果加了 <T>,SubOrder1 后面也必须加,这是语法规定
public class SubOrder1<T> extends Order<T> {
    
}

===================================================================================
    
public class GenericTest {

    @Test
    public void test2() {
        SubOrder1<String> sub1 = new SubOrder1<>();
        sub1.setOrderT("order1...");
        
        SubOrder1<Integer> sub2 = new SubOrder1<>();
        sub2.setOrderT(1122);
    } 
}
实例4:
public class GenericTest {

    @Test
    public void test3(){

        ArrayList<String> list1 = null;
        ArrayList<Integer> list2 = null;
        // 泛型不同的引用不能相互赋值。
        // 尽管在编译时 ArrayList<String> 和 ArrayList<Integer> 是两种类型,但是,在运行时只有一个 ArrayList 被加载到JVM中。 
        // list1 = list2;
    }
}
实例5:
// 当一个类中的某些内部结构(属性的类型、方法的入参类型、方法的返回值类型等)不能确定时,此时不确定的内部结构就可以使用泛型
public class Order<T> {

    // 下面这两个属性类型确定
    String orderName;
    int orderId;

    // 下面这个属性的类型不确定,此时就可以使用泛型
    T orderT;

	// 静态方法中不能使用类的泛型。
    // 下面代码编译报错
    public static void show(T orderT) {
        System.out.println(orderT);
    }
}
实例6:
// 这样写可以
public class MyException<T> {
    
}

============================================================

// 异常类不能声明为泛型类
public class MyException<T> extends Exception {
    
}

=============================================================
    
public class Order<T> {

    // 下面这两个属性类型确定
    String orderName;
    int orderId;

    // 下面这个属性的类型不确定,此时就可以使用泛型
    T orderT;

    public void show() {
        // 编译不通过
        try{

        }catch(T t){

        }
    }
}    
实例7:
public class Order<T> {

    // 下面这两个属性类型确定
    String orderName;
    int orderId;

    // 下面这个属性的类型不确定,此时就可以使用泛型
    T orderT;

    public Order(){
        // 编译不通过
        // T 只是一个变量,一个参数;只有当存在一个类且类的名字叫T的时候,下面的写法才正确
        // T[] arr = new T[10];
        // 编译通过
        T[] arr = (T[]) new Object[10];
    }
}   
实例8:
class Father<T1, T2> { 
} 

// 子类不保留父类的泛型 
// 1、没有类型 擦除 
class Son1 extends Father { // 等价于class Son extends Father<Object,Object> 
} 
// 2、具体类型 
class Son2 extends Father<Integer, String> { 
} 

// 子类保留父类的泛型 
// 1、全部保留 
class Son3<T1, T2> extends Father<T1, T2> { 
} 
// 2、部分保留 
class Son4<T2> extends Father<Integer, T2> { 
}

=========================================================================
    
class Father<T1, T2> { 
} 

// 子类不保留父类的泛型 
// 1、没有类型 擦除 
class Son<A, B> extends Father { // 等价于 class Son extends Father<Object,Object> 
}
// 2、具体类型 
class Son2<A, B> extends Father<Integer, String> { 
}

// 子类保留父类的泛型 
// 1、全部保留 
class Son3<T1, T2, A, B> extends Father<T1, T2> { 
} 
// 2、部分保留 
class Son4<T2, A, B> extends Father<Integer, T2> { 
}
实例9:
public class Order<T> {

    // 下面这两个属性类型确定
    String orderName;
    int orderId;

    // 下面这个属性的类型不确定,此时就可以使用泛型
    T orderT;

    // 下面的这两个方法都不是泛型方法
    public T getOrderT() {
        return orderT;
    }

    public void setOrderT(T orderT) {
        this.orderT = orderT;
    }
    
    // 泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系。
    // 换句话说,泛型方法所属的类是不是泛型类都没有关系。
    // 泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化类时确定。
    public static <E> List<E> copyFromArrayToList(E[] arr){

        ArrayList<E> list = new ArrayList<>();

        for(E e : arr){
            list.add(e);
        }
        
        return list;
    }
} 

public class GenericTest {
    // 测试泛型方法
    @Test
    public void test4() {
        Order<String> order = new Order<>();
        Integer[] arr = new Integer[]{1,2,3,4};
        // 泛型方法在调用时,指明泛型参数的类型。
        List<Integer> list = order.copyFromArrayToList(arr);

        System.out.println(list);
    }
}
posted @ 2020-08-31 22:38  kehuaihan  阅读(349)  评论(0编辑  收藏  举报