一、泛型(Generic)在集合中的使用

1.作用

(1)解决元素存储的安全问题

(2)解决获取数据元素时,需要类型强转的问题

2.代码案例

        //在集合没有使用泛型的情况下
        List list = new ArrayList();
        //list用来存放成绩
        list.add(60);
        list.add(70);
        list.add(80);
        //在没有使用泛型时,任何Object及其子类都可以添加进来,不安全
        list.add(new String("AA"));
        
        for(int i = 0; i < list.size();i++){
            //在强转字符串“AA”为int型时报ClassCastException的异常
            int score = (Integer)list.get(i);
            System.out.println(score);
        }
        //在集合中使用泛型
        List<Integer> list = new ArrayList<Integer>();
        //list用来存放成绩
        list.add(60);
        list.add(70);
        list.add(80);
        //list.add(new String("AA"));编译时就不通过,只能添加Integer类型的元素
        
        Iterator<Integer> it = list.iterator();//用Iterator也需要声明泛型为Integer
        while(it.hasNext()){
            System.out.println(it.next());
        }

二、自定义泛型类、泛型接口、泛型方法

 1.特点

(1)当实例化泛型类的对象时,指明泛型的类型,对应的类中所有使用泛型的位置,都变为指定的类型

(2)如果泛型类在实例化时没有指明泛型的类型,默认为Object类

(3)通过对象调用泛型方法时,指明泛型的类型,这个类型可以和泛型类的泛型的类型不一致。

(4)静态方法中不能使用类的泛型(因为类的泛型在实例化才指明类型,所以不能在静态方法中使用)

(5)不能在try-catch中使用泛型

2.代码示例

//自定义泛型类
public class Order<T> {//实例化后,类中的所有T都变为指定的类型
    private T t;
    List<T> list = new ArrayList<>();
    
    public void add(){
        list.add(t);
    }
    public T getT(){
        return t;
    }
    public void setT(T t){
        this.t = t;
    }
    //声明一个泛型方法,实现任意类型的数组到集合的复制
    public <E> List<E> fromArrayToList(E[] e,List<E> list){//注意“<E>”的位置,不能少
        for(E e1 : e){
            list.add(e1);
        }
        return list;
    }
}
//继承泛型类或泛型接口时,可以指明泛型的类型,也可以不指明
class SubOrder extends Order<Integer>{//class SubOrder<T> extends Order<T>{}
    
}
//泛型类的使用
public class TestGeneric{
    public static void main(String[] args){
        Order<Boolean> order = new Order<Boolean>();
        order.setT(true);//参数只能是Boolean类型的
        System.out.println(order.getT());//输出true
        order.add();
        List<Boolean> list = order.list;
        System.out.println(list);//输出[true]
        
        SubOrder o1 = new SubOrder();
        //只能用List<Integer>类型的List接收SubOrder类型的list。
        List<Integer> list1 = o1.list;
        
        Integer[] i = new Integer[](1,2,3);
        List<Integer> list2 = new ArrayList<>();
        List<Integer> list3 = order.fromArrayToList(i,list2);
        System.out.println(list2);//输出[1,2,3]
        System.out.println(list3);输出[1,2,3]
    }
}

 三、泛型与继承的关系以及通配符

1.泛型与继承的关系:即使类A是类B的子类,List<A>也不是List<B>的子接口。

        Object obj = null;
        String str = "AA";
        obj = str;//String是Object的子类,这么写没错
        
        Object[] obj1 = null;
        String[] str1 = new String[]("AA","BB","CC");
        obj1 = str1;//也没错
        
        List<Object> list = null;
        List<String> list1 = new ArrayList<String>();
        list = list1;//报错,类型不匹配
        //用反证法,假设list = list1正确
        //list.add(123);list可以传入Object类型的元素
        //String str = list.get(0);//报错,所以假设不正确

2.通配符—— ?

(1)特点

A:List<A>、List<B>. . . . . .都是List<?>的子类

B:? extends A:可以存放A及其子类

C:? super A:可以存放A及其父类

        List<?> list = null;
        List<Object> list1 = new ArrayList<Object>();
        List<String> list2 = new ArrayList<String>();
        list = list1;//没错,LIst<?>是List<Object>的父类
        list = list2;//没错,LIst<?>是List<String>的父类
        
        List<? extends Number> list3 = null;
        LIst<Integer> list4 = null;
        list3 = list4;//没错
        list3 = list1;//报错,只能是Number或Number的子类
        List<? super Number> list5 = null;
        list5 = list1;//没错

(2)通配符的使用

        List<String> list = new ArrayList<String>();
        list.add("AA");
        list.add("BB");
        List<?> list1 = list;
        //可以读取声明为通配符的集合类的对象
        Iterator<?> iterator = list1.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());//把next()返回的值都看成是Object类型的,所以可以读取
        }
        //不允许向声明为通配符的集合类的对象写入对象,唯一例外的是null
        list1.add("CC");//报错,不知道写入的是什么类型的对象
        list1.add(123);//报错
        list1.add(null);//正确