1.泛型概念:所谓泛型,就是允许在定义类,接口时,通过一个标识来表示类中某个属性的类型或者是某个方法的返回值及参数类型
2.基本使用

package com.yl.pdfdemo.day08.p2;

import org.junit.Test;

import java.util.*;

/**
 * @Author wfj
 * @Date 2021/6/25
 * @Description 泛型
 * @Version 1.0
 */

public class GenericTest {
    /**
     * 泛型概念:
     *      所谓泛型,就是允许在定义类,接口时,通过一个标识来表示类中某个属性的类型或者是某个方法的返回值及参数类型,
     *      这个类型参数将在使用时,例如继承或实现这个接口,用这个类型声明变量,创建对象时,确定(即传入实际的类型参数,也称为类型实参)
     *      jdk1.5以后,java引入了“参数化类型”的概念,允许我们在创建集合时,再指定集合元素的类型,正如List<String>,这表明该List只能保存String类型的对象
     */

    @Test
    public void test1() {
        //注意:泛型的类型必须是类,不可以是基本数据类型
        List<Integer> list = new ArrayList<>();
        list.add(11);
        list.add(2);
        list.add(3);
        //编译会报错
        //list.add("abc");
        for(int i : list) {
            System.out.println(i);
        }

        Map<String,Integer> map = new HashMap<>();
        map.put("a",1);
        map.put("b",2);
        //编译报错
        //map.put(1,1);
        Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator = entrySet.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Integer> entry = iterator.next();
            System.out.println("key:"+entry.getKey() + "value:"+entry.getValue());
        }
    }
}

3.自定义泛型类和自定义泛型方法

package com.yl.pdfdemo.day08.p2;

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

/**
 * @Author wfj
 * @Date 2021/6/25
 * @Description 自定义泛型类
 * @Version 1.0
 */

public class Order<T> {
    private String name;

    private int age;

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

    public T getOrderT() {
        return orderT;
    }

    public void setOrderT(T orderT) {
        this.orderT = orderT;
    }

    //泛型的构造器写法和普通类的构造器写法一致
    public Order() {
        //编译不通过,T不是具体的类,所有编译不会通过
//        T[] arr = new T[10];
        //编译通过
        T[] arr1 = (T[]) new Object[10];
    }

    public Order(String name, int age, T orderT) {
        this.name = name;
        this.age = age;
        this.orderT = orderT;
    }

    @Override
    public String toString() {
        return "Order{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", orderT=" + orderT +
                '}';
    }

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

4.测试用到的实体类

package com.yl.pdfdemo.day08.p2;

/**
 * @Author wfj
 * @Date 2021/6/25
 * @Description 不是泛型类,继承了泛型类了而已
 * @Version 1.0
 */

public class SubOrder extends Order<Integer> {
}
package com.yl.pdfdemo.day08.p2;

/**
 * @Author wfj
 * @Date 2021/6/25
 * @Description 该类是泛型类
 * @Version 1.0
 */

public class SubOrder1<T> extends Order<T> {
}
package com.yl.pdfdemo.day08.p2;

/**
 * @Author wfj
 * @Date 2021/6/25
 * @Description
 * @Version 1.0
 */

public class Person {
}
package com.yl.pdfdemo.day08.p2;

/**
 * @Author wfj
 * @Date 2021/6/25
 * @Description
 * @Version 1.0
 */

public class Student extends Person{
}

5.泛型在继承方面的体现以及通配符的基本使用

package com.yl.pdfdemo.day08.p2;

import org.junit.Test;

import java.util.*;

/**
 * @Author wfj
 * @Date 2021/6/25
 * @Description 自定义泛型类,接口,方法练习
 * @Version 1.0
 */

public class GenericTest1 {

    //自定义泛型类
    @Test
    public void test1() {
        //如果定义了泛型类,实例化没有指明类的泛型,则认为此泛型类型为Object类型
        //建议,如果定义了泛型类,那么在创建其对象时,应指明类的泛型
        //除此之外,静态方法中不可以使用类的泛型(因为泛型指定一般是在创建对象时指定的,而静态方法加载比构造器加载得早,编译不会通过),还有异常类不能是泛型类
        //继承时,子类可以保留亦或者不保留父类的泛型
        /**
         * class Father<T1,T2{}
         *1)没有类型,擦除
         * class Son1 extend Father{} 或者class Son1<A,B> extend Father{}//等价于class Son1 extend Father<Object,Object>{}
         * 2)具体类型
         * class Son2 extends Father<Integer,String>{} 或者 class Son2<A,B> extends Father<Integer,String>{}
         * 3)子类保留父类的泛型
         * 3.1)全部保留
         * class Son3<T1,T2> extends<T1,T2>{} 或者 class Son3<A,B,T1,T2> extends<T1,T2>{}
         * 3.2)部分保留
         * class Son4<T2> extends<Integer,T2>{} 或者 class Son4<T2,A,B> extends<Integer,T2>{}
         */
        Order order = new Order();
        order.setOrderT(123);
        order.setOrderT("qq");

        Order<String> order1 = new Order<>("咪咪",17,"solo");
        System.out.println(order1);

        SubOrder subOrder = new SubOrder();
        subOrder.setOrderT(123);

        SubOrder1<Double> subOrder1 = new SubOrder1<>();
        subOrder1.setOrderT(2.0);
    }

    //泛型方法的调用
    @Test
    public void test2() {
        Order<Integer> order = new Order<>();
        Integer[] arr = {1,2,3};
//        Integer[] arr = new Integer[]{1,2,3};
        //泛型方法在调用时,指明泛型参数的类型,我这里指定arr为Integer类型数组
        List<Integer> list = order.addArr(arr);
        for (Integer i : list) {
            System.out.println(i);
        }
    }

    /**
     * 泛型在继承方面的体现
     * 虽然A类是B类的父类,但是G<A> 和G<B> 不是父类关系,二者是并列关系
     * 注意:如果A类是B类的父类,那么A<G>是B<G>的父类
     */
    @Test
    public void test3() {
        //举例
        List<Object> list1 = new ArrayList<>();
        List<Integer> list2 = new ArrayList<>();
        //编译不会通过(因为list2存的是Integer类型数据,如果list1也指向了list2所指向的内存空间,list可以添加其他的比如String类型的数据
        // 这就导致list2集合里的元素的数据类型不一致了,故编译不会通过)
        //list1 = list2;

        //如下编译通过
        List<String> list3 = null;
        ArrayList<String> list4 = null;
        list3 = list4;
    }

    //通配符的使用 ?
    @Test
    public void test4() {
        /**
         * 通配符 ?
         *
         * 类A是类B的父类,G<A>和G<B>是没有任何关系的,二者共同的父类是G<?>
         */
        List<Object> list = null;
        List<String> list1 = null;

        List<?> list2 = null;
        list2 = list;
        list2 = list1;
        show(list);
        show(list1);

        List<String> list3 = new ArrayList<>();
        list3.add("aa");
        list3.add("bb");
        list3.add("cc");
        list2 = list3;
        //添加,对于list而言,其不能添加元素,除了null之外
        //list2.add()

        //读取数据
        Object o = list2.get(0);
        System.out.println(o);//"aa"
    }

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

    //有限制条件的通配符的使用
    // ? extends 类    类似小于等于
    //      G<? extends A> 可以作为G<A>和G<B>的父类,其中B是A的子类
    // ? super 类      类似大于等于
    //      G<? super A> 可以作为G<A>和G<B>的父类,其中B是A的父类
    @Test
    public void test5() {
        List<? extends Person> list1 = null;
        List<? super Person> list2 = null;
        List<Student> list3 = new ArrayList<>();
        List<Person> list4 = new ArrayList<>();
        List<Object> list5 = new ArrayList<>();
        list1 = list3;
        list1 = list4;
        //编译不通过
        //list1 = list5;

        //编译不通过
       // list2 = list3;
        list2 = list4;
        list2 = list5;

        //读取数据
        list1 = list3;
        Person person = list1.get(0);
        //编译不通过,只能取最小的那个类,最小代表被继承的那个类
        //Student student = list1.get(0);

        list2 = list4;
        Object object = list2.get(0);
        //编译不通过,只能取最大的那个类
        //Person person1 = list2.get(0);

        //添加数据(规律,只能添加左边开始最小的)
        //编译不通过,这是为什么呢?
        /**
         * 因为? extends Person   类似于(负无穷,Person]
         * 这里Student虽然继承了Person,但是负无穷代表可能也有一些类假设是A类继承了Student类的,如果我们往里面添加Student对象,显然是不正确的
         * 因为父类不能赋值给子类
         */
        //list1.add(new Student());

        //编译通过,? super Person 类似于 [Person,正无穷)
        list2.add(new Person());
        list2.add(new Student());


    }

}

6.泛型的使用场景

1)实体类

Java泛型通配符T获取class名称_泛型


Java泛型通配符T获取class名称_Java泛型通配符T获取class名称_02

2)通用Dao

Java泛型通配符T获取class名称_Java泛型通配符T获取class名称_03

3)实体类对应的DAO

Java泛型通配符T获取class名称_List_04


Java泛型通配符T获取class名称_泛型_05

4)测试

Java泛型通配符T获取class名称_泛型_06


7.案例

1)实体类

package com.yl.pdfdemo.day08.p2;

import java.util.Objects;

/**
 * @Author wfj
 * @Date 2021/6/25
 * @Description
 * @Version 1.0
 */

public class User {
    private int id;
    private int age;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public User() {
    }

    public User(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return id == user.id &&
                age == user.age &&
                Objects.equals(name, user.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, age, name);
    }
}

2)DAO

package com.yl.pdfdemo.day08.p2;

import java.util.*;

/**
 * @Author wfj
 * @Date 2021/6/25
 * @Description
 * @Version 1.0
 */

public class Dao<T> {

    private Map<String,T> map = new HashMap<>();

    public void save(String id, T entity) {
        map.put(id,entity);
    }
    public T get(String id) {
        return map.get(id);
    }
    public void update(String id, T entity) {
        if (map.containsKey(id)) {
            map.put(id,entity);
        }
    }
    public List<T> list() {
        //错误写法
//        Collection<T> values = map.values();
//        return (List<T>)values;
        ArrayList<T> list = new ArrayList<>();
        Collection<T> values = map.values();
        for (T t : values) {
            list.add(t);
        }
        return list;
    }
    public void remove(String id) {
        map.remove(id);
    }

}

3)测试

package com.yl.pdfdemo.day08.p2;

import java.util.List;

/**
 * @Author wfj
 * @Date 2021/6/25
 * @Description
 * @Version 1.0
 */

public class DaoTest {
    public static void main(String[] args) {
        Dao<User> dao = new Dao<>();
        dao.save("001",new User(1001,25,"小白"));
        dao.save("002",new User(1002,21,"小兰"));
        dao.save("003",new User(1003,22,"小飞"));
        List<User> list = dao.list();
        list.forEach(System.out::println);
//        User{id=1001, age=25, name='小白'}
//        User{id=1002, age=21, name='小兰'}
//        User{id=1003, age=22, name='小飞'}
    }
}