泛型

泛型的使用

  • 1.jdk5.0新增特性
  • 2.在集合中使用泛型
1、集合接口或集合类在jdk5.0时都修改为带泛型的结构    
2、在实例化集合类时,指明具体的泛型类型
  • 3、指明类型后,在集合类或接口中凡是定义类或接口时,内部结构(方法、构造器、属性)等使用泛型的位置都指定为实例化的泛型类型
    比如:add(E e) —>实例化后add(Integer e)
  • 4、注意:泛型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,使用包装类替换
  • 5.如果实例化时,没有指明泛型的类型。默认类型为Object类型

在集合中不使用泛型

@Test
    //在集合中不使用泛型的情况
    public void test(){
        ArrayList list = new ArrayList();
        list.add(123);
        list.add(23);
        list.add(245);
        //问题一:类型不安全
        list.add("zmj");

        //遍历
        for(Object obj : list){
            //问题二:强转时,可能出现异常ClassCastException
            Integer integer = (Integer) obj;
            System.out.println(integer);
        }
    }

在集合中使用泛型

  • 指明泛型后,非泛型指定类型直接会在编译时进行类型检查,保证数据的安全
@Test
public void test1(){
    ArrayList<Integer> list = new ArrayList<>();
    list.add(123);
    list.add(23);
    list.add(245);
    //指明泛型后,非泛型指定类型直接会在编译时进行类型检查,保证数据的安全
    //list.add("zmj");

    //遍历
    for(Integer integer : list){
        System.out.println(integer);
    }
}

    @Test
    public void test3(){

        //在集合中使用泛型的情况:以HashMap为例
        HashMap<String, Integer> map = new HashMap<>();
        map.put("AA",123);
        map.put("CC",125);
        map.put("BB",124);

        //遍历所有的key
        Set<String> set = map.keySet();
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println("**********");
        //遍历所有的value
        Collection<Integer> values = map.values();

        for(Integer integer:values){
            System.out.println(integer);
        }

        //遍历所有的key-value
        //方式一、entrySet()
        Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator1 = entrySet.iterator();
        while (iterator1.hasNext()){
            //entrySet集合中的元素都是entry
            Map.Entry<String, Integer> entry = iterator1.next();

            System.out.println(entry.getKey() + "===>" + entry.getValue());
        }

//        //遍历所有的key-value
//        //方式二、分别遍历key和value,然后显示
//        Set set1 = map.keySet();
//        Collection values1 = map.values();
//        Iterator iterator2=set.iterator();
//        Iterator iterator3=values.iterator();
//        while (iterator2.hasNext()&&iterator3.hasNext()){
//            System.out.println(iterator2.next() + "===>" + iterator3.next());
//        }
//
    }

泛型类

  • 静态方法中不能使用类的泛型
  • 异常类不能使用泛型
/**
 * Created by KingsLanding on 2022/6/29 15:03
 */
public class Order<T> {
    String orderName;
    int orderId;

    //类的内部结构就可以使用类的泛型
    T orderT;

    public Order() {
    }

    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 static void show(T orderT){
//
//    }
    //异常类不能使用泛型

    //泛型方法:在方法中出现的泛型结构,泛型参数和类的泛型参数没有任何关系
    //泛型方法所属的类是不是泛型类都无所谓
    //泛型方法可以声明为静态的。原因:泛型参数是在调用方法是才确定的,并非在实例化时确定
    public <E> List<E> copyFromArrayToList(E[] arr){
        ArrayList<E> list = new ArrayList<>();
        for(E e : arr){
            list.add(e);
        }
        return list;
    }
    
}

泛型类的实例化

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

    //指明实例化时类的泛型
    Order<String> order1 = new Order<String>("zmj",12,"ZMJ");
    
  //  Order<String> order1 = new Order<String>("zmj",12,20);//指定了泛型,这里就不能设置为除String之外的数据了
}

泛型方法

//泛型方法:在方法中出现的泛型结构,泛型参数和类的泛型参数没有任何关系
//泛型方法所属的类是不是泛型类都无所谓
//泛型方法可以声明为静态的。原因:泛型参数是在调用方法是才确定的,并非在实例化时确定
public <E> List<E> copyFromArrayToList(E[] arr){
    ArrayList<E> list = new ArrayList<>();
    for(E e : arr){
        list.add(e);
    }
    return list;
}

方法调用

@Test
public void test2(){
    Order<String> order = new Order<>();
    Integer[] arr = new Integer[]{1,2,3,4};
    //泛型方法在调用是,指明泛型参数的类型
    List<Integer> list = order.copyFromArrayToList(arr);
    System.out.println(list);
}

泛型在继承中的体现

非泛型类继承泛型类

public class SubOrder extends Order<Integer>{//SubOrder不是泛型类
    
}

泛型类之间的继承

/**
 * Created by KingsLanding on 2022/6/29 15:14
 */
public class SubOrder1<T> extends Order<T> {//SubOrder1<T>仍然是泛型类

}

实例化

public void test1(){
    SubOrder subOrder = new SubOrder();
    //由于子类在继承带泛型的父类时,指明了泛型类型,则实例化子类对象时,不需要指明泛型,只能遵循父类的要求
    subOrder.setOrderT(12);

    SubOrder1<String> stringSubOrder1 = new SubOrder1<>();
    stringSubOrder1.setOrderT("zmj");
}
  • 虽然类A是B的父类,但是G 和G二者不具备子父类关系,二者是并列关系
  • 补充:类A是类B父类,A 的父类
/*
    1.泛型在继承方面的体现

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

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

    public void test(){
        Object obj=null;
        String str=null;
        obj=str;

        //没有子父类关系,编译不通过
//        Date date=null;
//        str=date;

        Object[] arr1=null;
        String[] arr2=null;
        arr1=arr2;

        List<Object> list=null;
        List<String> list1 =null;
        //此时的list和list1的类型不具有子父类关系,编译不通过
//        list= list1;

    }

    public void test2(){

        List<String> list1=null;
        ArrayList<String> list2=null;
		//此时的list1和list1的类型具有子父类关系,编译通过
        list1 = list2;
    }

通配符

  • 通配符:?

通配符的使用

@Test
    public void test3(){
        /*
        2.通配符的使用
          通配符:?
         */
        List<Object> list=new ArrayList<>();
        List<String> list1=new ArrayList<>();
        list.add(123);
        list1.add("zmj");

        List<?> list2=null;
        list2=list;
        list2=list1;

        //添加:对于List<?>不能向其内部添加数据
        //除了添加null之外
//        list2.add("除了null都添加不了");
        list2.add(null);
        //获取:允许读取数据,读取的数据类型为Object
        Object o = list2.get(0);
        System.out.println(o);

        //通配符使用:同一个方法可以传不同类型的集合
        test4(list);
        test4(list1);
    }

    public void test4(List<?> list){

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

有限制条件的通配符

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

父类

/**
 * Created by KingsLanding on 2022/6/29 19:42
 */
public class Person {
}

子类

/**
 * Created by KingsLanding on 2022/6/29 19:42
 */
public class Student extends Person {
}
/*
    3.有限制条件的通配符的使用
        ?extends A:
        G<? extends A>  可以作为G<A>和G<B>的父类,其中B是A的子类 <=
        G<? super A>    可以作为G<A>和G<B>的父类,其中B是A的父类 >=
     */
    public void test5(){

       List<Student> student = new ArrayList<>();
       List<Person> person = new ArrayList<>();
       List<Object> obj = new ArrayList<>();


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

       list = student;
       list = person;
       //编译不通过,<=
//       list = obj;

        //编译不通过,>=
//        list1=student;
        list1=person;
        list1=obj;

        //读取数据
        Person person1 = list.get(0);
        //编译不通过
//        Student stu = list.get(0);

        Object object = list1.get(0);
        //编译不通过
//        Person pson = list1.get(0);

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

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