一、概述

自定义泛型的作用是用来规定一个类, 接口或方法所能接受的数据的类型。泛型中没有多态的概念,两边的数据必须要一致,或者只写一边的泛型类型(兼容老版本)。

二、泛型的好处

①将运行时出现的错误提前到了编译时


②避免了类型强转的麻烦


三、自定义泛型方法

①定义格式:修饰符  <自定义泛型>返回值类型    函数名(自定义泛型 变量名){ }


②注意:


a. 在方法上的自定义泛型的具体数据类型是调用该方法的时候传入实参的时候确定的。


b. 自定义泛型使用的标识符只要符合标识符的命名规则即可。


四、自定义泛型类

① 定义格式:

class 类名<自定义泛型>{ }


② 如果静态的方法需要使用自定义泛型,那么需要在方法上自己声明使用。


③ 泛型类注意的事项: 


a.在类上自定义的泛型的具体数据类型是在创建对象的时候指定的。


b.在类上自定义了泛型,如果创建该类的对象时没有指定泛型的具体类型,那么默认是Object类型。


例:


//自定义类上的泛型  
public class Demo1<T> {


    //自定义带泛型的方法  
	public <T>T funtion(T t) {  
          
        return null;  
    }  
      
    public <T,E,K>void b(T t,E e,K k) {  
          
    }  
  
    //静态方法泛型定义在static后   
    public static<T> void c(T t) {  
          
    }  
}
五、自定义泛型接口

① 定义格式:

interface 接口名<声明自定义泛型>{ }


② 延长接口自定义泛型的具体数据类型到类:

class 类名<T> implements 接口名<T>{ }


③在接口上自定义泛型要注意的事项:


a.在接口上自定义泛型的具体数据类型是在实现该接口的时候指定的。


b.如果一个接口自定义了泛型,在实现该接口的时候没有指定具体的数据类型,那么默认是Object数据类型。 


例:


//泛型接口的定义
public interfaceInter<T> {  
    public abstract void show(T t);
}


//泛型接口的实现
public classInterImpl<T> implements Inter<T>{  


    @Override
    public void show(T t) {
        System.out.println(t);
    }
}


//泛型接口的测试
public classInterDemo {  
    public static void main(String[] args) {
        Inter<String> i = new InterImpl<String>();
        i.show("hello");
        Inter<Integer>i1 = newInterImpl<Integer>();
        i1.show(30);
    }
}
六、泛型中通配符


1. <?>


无边界的通配符,让泛型能够接受未知类型的数据,例:


public static void printList(List<?> list) {
    for (Object o : list) {
        System.out.println(o);
    }
}

public static void main(String[] args) {
    List<String> l1 = new ArrayList<>();
    l1.add("aa");
    l1.add("bb");
    l1.add("cc");
    printList(l1);
    List<Integer> l2 = new ArrayList<>();
    l2.add(11);
    l2.add(22);
    l2.add(33);
    printList(l2);
    
}


2. <? extends T>


泛型的上限,参数类型必须是T或T的子类型,如:


? extends Number

只能存储Number或者是Number类型的子类数据。


3. <? super T>


泛型的下限,参数类型必须是T或T的超类型,如:


? super Integer

只能存储Integer或者是Integer父类元素。