Java高级部分笔记之泛型

文章目录

Java泛型

集合中使用泛型举例

package com.test.java3;

import org.junit.Test;

import java.util.*;

/*
    泛型的使用
    1、JDK 5.0新增的特性

    2、在集合中使用泛型:
        总结:
            ① 集合接口或集合类在JDK5.0时都修改为带泛型的结构。
            ②  在实例化集合类时,可以指明具体的泛型类型
            ③ 指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如: 方法、构造器、属性等)使用到类的泛型的位置,
            都指定为实例化的泛型类型
                比如: add(E e) ---> 实例化以后: add(Integer e)

            ④ 注意点: 泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换

            ⑤ 如果实例化时,没有指明泛型的类型。默认类型为java.lang.Object类型。
            
        3、如何自定义泛型结构: 泛型类、泛型接口、泛型方法
            
 */
public class GenericTest {

    //在集合中使用泛型之前的情况: 以ArrayList为例
    @Test
    public void test1(){

        ArrayList list = new ArrayList();

        //需求: 存放学生的成绩
        list.add(78);
        list.add(76);
        list.add(89);
        list.add(88);

        //问题一: 类型不安全
      //  list.add("Tom");

        for (Object score : list){
            //问题二: 强转时,可能出现ClassCastException
            int stuScore = (Integer) score;
            System.out.println(stuScore);
        }
    }
    //在集合中使用泛型的情况:
    @Test
    public void test2(){
        //使用泛型时不可使用基本数据类型
        ArrayList<Integer> list = new ArrayList<>();

        list.add(78);
        list.add(87);
        list.add(99);
        list.add(65);
       //编译时,就会进行类型检查,保证数据的安全

  //      list.add("Tom");

        //方式一:
        for (Integer score : list){
            //避免了强转操作
            int stuScore = score;
            System.out.println(stuScore);
        }

        //方式二:
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()){
            int stuScore = iterator.next();
            System.out.println(stuScore);

        }
    }

    //在集合中使用泛型之前的情况: 以HashMap为例
    @Test
    public void test3(){
        Map<String,Integer> map = new HashMap<String,Integer>();

        map.put("Tom",87);
        map.put("Jerry",87);
        map.put("Jack",67);

      //  map.put(123,"ABC");

        //泛型的嵌套
        Set<Map.Entry<String, Integer>> entry = map.entrySet();

        Iterator<Map.Entry<String, Integer>> iterator = entry.iterator();

        while(iterator.hasNext()){
            Map.Entry<String,Integer> e = iterator.next();
            String key = e.getKey();
            Integer value = e.getValue();
            System.out.println(key+"----"+value);

        }
    }
}

自定义泛型类举例

package com.test.java3;

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


}

package com.test.java3;

public class SubOrder1<T> extends Order<T>{//SubOrder1<T> : 仍然是泛型类


}

package com.test.java3;

import org.junit.Test;

/*
        如何自定义泛型结构: 泛型类、泛型接口、泛型方法.

            1、关于自定义泛型类、泛型接口:


    */
public class GenericTest1 {

    @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");


    }
    @Test
    public void test2(){
        SubOrder sub1 = new SubOrder();
        //由于子类在继承带泛型的父类时,指明了泛型类型。则实例化子类对象时,不再需要指明泛型。
        sub1.setOrderT(123);

        SubOrder1<String> sub2 = new SubOrder1<String>();
        sub2.setOrderT("AA");
    }

}

自定义泛型类泛型接口的注意点

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

    public Order(){
        //编译不通过
   //    T[] arr = new T[10];
        //编译通过
        T[] arr = (T[]) new Object[10];

    };

//静态方法中不能使用类的泛型。
//    public static void show(T orderT){
//        System.out.println(orderT);
//    }

    public void show(){
        //编译不通过
//        try{
//
//        }catch (T t){
//
//        }
    }

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

}

自定义泛型方法举例


    //泛型方法: 在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系。
    //换句话说,泛型方法所属的类是不是泛型类都没有关系。
    //泛型方法,可以声明为静态的。原因: 泛型参数是在调用方法时确定的,并非在实例化类时确定。

    public static <E> List<E> copyFromArrayToList(E[] arr){
        ArrayList<E> list = new ArrayList<>();

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

        }
        return list;
    }
package com.test.java3;

import java.util.ArrayList;
import java.util.List;

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

    public static <E> List<E> copyFromArrayToList(E[] arr){
        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);

    }

举例泛型类和泛型方法的使用情境

package com.test.java4;

import java.util.List;

/*
    DAO: data(base) access object(数据访问对象)



 */
public class DAO<T> {//表的共性操作的DAO

    // 添加一条记录
    public void add(T t){

    }
    //删除一条记录
    public boolean remove(int index){
        return false;
    }
    //修改一条记录
    public void update(int index,T t){

    }
    //查询一条记录
    public T getIndex(int index){
        return null;
    }
    //查询多条记录
    public List<T> getForList(int index){
        return null;
    }

    //泛型方法
    //举例: 获取表中一个多少条记录?获取最大的员工入职时间?
    
    public <E> E getValue(){
        return null;
    }

}

package com.test.java4;

public class Customer {//此类对应数据库中的customers表

}
package com.test.java4;

public class Student {
}

package com.test.java4;

public class CustomerDAO extends DAO<Customer>{//只能操作一个表


}

package com.test.java4;

public class StudentDAO extends DAO<Student>{//只能操作一个表

}

package com.test.java4;

import org.junit.Test;

import java.util.List;

public class DAOTest {
    @Test
    public void test1(){
        CustomerDAO dao1 = new CustomerDAO();
        dao1.add(new Customer());
        List<Customer> list = dao1.getForList(10);

        StudentDAO dao2 = new StudentDAO();

    }
}

泛型在继承方面的体现

package com.test.java5;

import org.junit.Test;

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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

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

                补充: 类A是类B的父类,A<G> 是B<G>的父类
        2、通配符的使用:


    */
public class GenericTest {
    /*
        1、泛型在继承方面的体现

     */
        @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 = null;
//          此时的list1和list2的类型不具有子父类关系
//            list1 = list2;

            /*
                反证法:
                    假设list1 = list2;
                    list1.add(123);导致混入非String的数据。出错。

             */
            show(list1);
            show1(list2);

        }
    public void show1(List<String> list){}
    public void show(List<Object> list){}

    @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);


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

使用通配符后数据的读取和写入要求

@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(null);

        //获取(读取): 允许读取数据,读取的数据类型为Object

        Object o = list.get(0);
        System.out.println(o);

    }

有限制条件的通配符的使用

 /*
        3、有限制条件的通配符的使用
            ? extends Person: G<? ectends A> 可以作为G<A>和G<B>的父类的,其中B是A的子类
            ? super Person: G<? super A> 可以作为G<A>和G<B>的父类的,其中B是A的父类
     */
    @Test
    public void test4() {

        List<? extends Person> list1 = null;
        //可以是Person类或者Person的子类
        List<? super Person> list2 = null;


        List<Student> list3 = null;
        List<Person> list4 = null;
        List<Object> list5 = null;

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

//可以是Person类或者Person的父类
       // list2 = list3;
        list2 = list4;
        list2 = list5;

    }

   /*
        3、有限制条件的通配符的使用
            ? extends Person: G<? ectends A> 可以作为G<A>和G<B>的父类的,其中B是A的子类
            ? super Person: G<? super A> 可以作为G<A>和G<B>的父类的,其中B是A的父类
     */
    @Test
    public void test4() {

        List<? extends Person> list1 = null;
        //可以是Person类或者Person的子类
        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;

        //可以是Person类或者Person的父类
        // list2 = list3;
        list2 = list4;
        list2 = list5;

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


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


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

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

上一篇:DDD分层架构的三种模式


下一篇:Python 将两个列表转换成字典最快的方式