Java高级 - 泛型

54 阅读2分钟

为什么要有泛型

泛型的概念

为什么要有泛型

泛型使用

自定义泛型结构

案例:

子类不去搞泛型默认那就是Object类型了。

泛型方法

例子

T 要是 Person 的子类

案例

声明方法

//泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系。
//换句话说,泛型方法所属的类是不是泛型类都没有关系。
//泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化类时确定。
public static <E>  List<E> copyFromArrayToList(E[] arr){
    //指定泛型的字母	 泛型标签				泛型数组
    //如果不指定 E 的话,后面的泛型数组以为是一个对象,从而导致编译失败        

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

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

}

调用

//测试泛型方法
@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);
}

实际使用

除了集合里面使用外,ORM框架也是经常使用的

泛型在继承上的体现

就像 List 和 List 是不一样的类型,不能相互负责,虽然Object是String的父类,但是这两者没任何关系 List 和 List

通配符的使用

类、方法和创建对象时都不能用,那就只能在声明对象的时候使用了

/*
    1. 泛型在继承方面的体现

      虽然类A是类B的父类,但是G<A> 和G<B>二者不具备子父类关系,二者是并列关系。

       补充:类A是类B的父类,A<G> 是 B<G> 的父类

     */
    @Test
    public void test1(){

        Object obj = null;
        String str = null;
        obj = str;

        Object[] arr1 = null;
        String[] arr2 = null;
        arr1 = arr2;
        //编译不通过
//        Date date = new Date();
//        str = date;
        List<Object> list1 = null;
        List<String> list2 = new ArrayList<String>();
        //此时的list1和list2的类型不具有子父类关系
        //编译不通过
//        list1 = list2;
        /*
        反证法:
        假设list1 = list2;
           list1.add(123);导致混入非String的数据。出错。

         */

        show(list1);
        show1(list2);

    }
@Test
    public void test2(){

        AbstractList<String> list1 = null;
        List<String> list2 = null;
        ArrayList<String> list3 = null;

        list1 = list3;
        list2 = list3;

        List<String> list4 = new ArrayList<>();

    }

    /*
    2. 通配符的使用
       通配符:?

       类A是类B的父类,G<A>和G<B>是没有关系的,二者共同的父类是:G<?>


     */

    @Test
    public void test3(){
        List<Object> list1 = null;
        List<String> list2 = null;

        List<?> list = null;

        list = list1;
        list = list2;
        //编译通过
//        print(list1);
//        print(list2);


        //
        List<String> list3 = new ArrayList<>();
        list3.add("AA");
        list3.add("BB");
        list3.add("CC");
        list = list3;
        //添加(写入):对于List<?>就不能向其内部添加数据。
        //除了添加null之外。
//        list.add("DD");
//        list.add('?');

        list.add(null);

        //获取(读取):允许读取数据,读取的数据类型为Object。
        Object o = list.get(0);
        System.out.println(o);


    }

    public void print(List<?> list){
        Iterator<?> iterator = list.iterator();
        while(iterator.hasNext()){
            Object obj = iterator.next();
            System.out.println(obj);
        }
    }

有限制的通配符

/*
3.有限制条件的通配符的使用。
    ? extends A:
            G<? extends A> 可以作为G<A>和G<B>的父类,其中B是A的子类

    ? super A:
            G<? super A> 可以作为G<A>和G<B>的父类,其中B是A的父类

 */
@Test
public void test4(){

    List<? extends Person> list1 = null;
    List<? super Person> list2 = null;

    List<Student> list3 = new ArrayList<Student>();
    List<Person> list4 = new ArrayList<Person>();
    List<Object> list5 = new ArrayList<Object>();

    list1 = list3;
    list1 = list4;
//        list1 = list5;

//        list2 = list3;
    list2 = list4;
    list2 = list5;

    //读取数据:
    list1 = list3;
    Person p = list1.get(0);
    //编译不通过
    //Student s = list1.get(0);

    list2 = list4;
    Object obj = list2.get(0);
    ////编译不通过
//        Person obj = list2.get(0);

    //写入数据:
    //编译不通过
//        list1.add(new Student());

    //编译通过
    list2.add(new Person());
    list2.add(new Student());

}