泛型
泛型
使用传统方法问题解析
1.不能对加入到集合 ArrayList 中的数据类型进行约束(不安全)
2.遍历的时候需要进行类型转换,如果集合中的数据量较大,对效率有影响
使用泛型的好处
1.编译时,检查添加元素的类型,提高了安全性
2.减少了类型转换的次数,提高了效率 --> 遍历时直接取出,不同进行类型转换
介绍
1.泛型又称参数化类型,是JDK5.0出现的新特性,解决数据类型的安全性问题
2.在类声明或实例化时,只需要指定好需要的具体的类型即可
3.Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常.同时代码更加简洁,健壮
4.泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值类型,或者是参数类型
第三点详解:有如下写法
public class ArrayList<E>{}
在这里,这个 E 我们称之为泛型
第四点详解:
class Person<E>{
  E s;  // E表示 s的数据类型,该数据类型在定义Person对象的时候指定
  // 即在编译期间,就确定E是什么类型
  
  // E也可以是参数类型
  public Person(E s){
  }
  
  // 返回类型使用E
  public E f(){
    return s;
  }
}
PS: E表示 s的数据类型,该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
语法
声明
interface 接口
比如: List , ArrayList
说明
- 1.其中,T,K,V不代表值,而是表示类型
 - 2.任意字母都可以.通常T表示,是Type的缩写
 
实例化
要在类名后面指定类型参数的值(类型),如:
- 1.
List<String> list = new ArrayList<String>(); - 2.
Iterator<Customer> iterator = customer.iterator(); 
使用练习
package javaSEStudy.generic;
import java.util.*;
// 泛型使用
@SuppressWarnings({"all"})
public class Generic {
    public static void main(String[] args) {
        // 使用泛型给HashSet添加对象
        HashSet<Student> student = new HashSet<Student>();
        student.add(new Student("Jack", 11));
        student.add(new Student("Tom", 25));
        student.add(new Student("Marry", 18));
        // 遍历
        for (Student s : student) {
            System.out.println(s);
        }
        System.out.println("-------------------------------------");
        // 使用泛型给HashMap添加对象
        HashMap<String, Student> map = new HashMap<String, Student>();
        map.put("Jack", new Student("Jack", 11));
        map.put("Tom", new Student("Tom", 25));
        map.put("Marry", new Student("Marry", 18));
        // 遍历
        Set<Map.Entry<String, Student>> entry = map.entrySet();
        Iterator<Map.Entry<String, Student>> iterator = entry.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Student> entry1 = iterator.next();
            System.out.println(entry1.getKey() + ":" + entry1.getValue());
        }
    }
}
class Student {
    private String name;
    private int age;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
使用
泛型的使用事项和细节
- interface  List
{}, public class HashSet {} 等 
说明:T,E 只能是引用类型 - 在指定泛型的具体类型后,可以传入该类型或者其子类类型
 - 泛型的使用类型
Listlist1 = new ArrayList (); 
Listlist2 = new ArrayList<>(); // 开发中经常如此简写 
ps:如果我们这么写 List list = new ArrayList(); 即默认给的泛型是[,E 是 Object]  
课堂练习

package javaSEStudy.generic.test;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
// 员工类排序
@SuppressWarnings({"all"})
public class Test1 {
    public static void main(String[] args) {
        Employee e1 = new Employee("张三", 1200.0, new MyDate(2002, 2, 1));
        Employee e2 = new Employee("李四", 1200.0, new MyDate(2001, 3, 10));
        Employee e3 = new Employee("李四", 1200.0, new MyDate(2001, 3, 9));
        Employee e4 = new Employee("王五", 1200.0, new MyDate(2005, 12, 21));
        Employee e5 = new Employee("王五", 1200.0, new MyDate(2006, 12, 21));
        ArrayList<Employee> list = new ArrayList<>();
        list.add(e1);
        list.add(e2);
        list.add(e3);
        list.add(e4);
        list.add(e5);
        list.sort(new Comparator<Employee>() {
            @Override
            public int compare(Employee o1, Employee o2) {
                // 这里防止子类传入
                if (!(o1 instanceof Employee && o2 instanceof Employee && o1 != null && o2 != null)) {
                    return 0;
                }
                int nameCompare = o1.getName().compareTo(o2.getName());
                if (nameCompare != 0) {
                    return nameCompare;
                }
                // 比较的代码可以放如Date中,封装性更好
//                int year = o1.getBirthday().getYear() - o2.getBirthday().getYear();
//                int yearCompare = Integer.compare(o1.getBirthday().getYear(), o2.getBirthday().getYear());
//                if (yearCompare != 0) {
//                    return yearCompare;
//                }
//
//                int monthCompare = Integer.compare(o1.getBirthday().getMonth(), o2.getBirthday().getMonth());
//                if (monthCompare != 0) {
//                    return monthCompare;
//                }
//
//                return Integer.compare(o1.getBirthday().getDay(), o2.getBirthday().getDay());
//            }
                return o1.getBirthday().compareTo(o2.getBirthday());
            }
        });
        Iterator<Employee> iterator = list.iterator();
        while (iterator.hasNext()) {
            Employee next = iterator.next();
            System.out.println(next.getName() + "," +
                    next.getSalary() + ", " +
                    next.getBirthday().getYear() + ":" +
                    next.getBirthday().getMonth() + ":" +
                    next.getBirthday().getDay());
        }
    }
}
class Employee {
    private String name;
    private Double salary;
    private MyDate birthday;
    public Employee(String name, Double salary, MyDate birthday) {
        this.name = name;
        this.salary = salary;
        this.birthday = birthday;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Double getSalary() {
        return salary;
    }
    public void setSalary(Double salary) {
        this.salary = salary;
    }
    public MyDate getBirthday() {
        return birthday;
    }
    public void setBirthday(MyDate birthday) {
        this.birthday = birthday;
    }
    @Override
    public String toString() {
        return "name='" + name + '\'' +
                ", salary=" + salary +
                ", birthday=" + birthday;
    }
}
class MyDate implements Comparable<MyDate> {
    private int year;
    private int month;
    private int day;
    public MyDate(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }
    public int getYear() {
        return year;
    }
    public void setYear(int year) {
        this.year = year;
    }
    public int getMonth() {
        return month;
    }
    public void setMonth(int month) {
        this.month = month;
    }
    public int getDay() {
        return day;
    }
    public void setDay(int day) {
        this.day = day;
    }
    @Override
    public String toString() {
        return "year=" + year +
                ", month=" + month +
                ", day=" + day;
    }
    @Override
    public int compareTo(MyDate o) {
        int yearCompare = year - o.year;
        if (yearCompare != 0) {
            return yearCompare;
        }
        int monthCompare = month - o.month;
        if (monthCompare != 0) {
            return monthCompare;
        }
        return day - o.day;
    }
}
自定义泛型
基本语法
// 也可以是接口
// 这里... 是可以有多个
class 类名<T,R...>{
  成员
}
注意细节
- 1.普通成员可以使用泛型(属性,方法)
 - 2.使用泛型的数组,不能初始化
 - 3.静态方法中不能使用类的泛型
 - 4.泛型类的泛型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
 - 5.如果创建对象时,没有指定类型,默认为Object
 
话不多说,代码展示
package javaSEStudy.generic.customGeneric;
// 自定义泛型
public class CustomGeneric_ {
    public static void main(String[] args) {
    }
}
/**
 * Tiger 后面就是泛型,我们将 Tiger 称之为自定义泛型
 * T R M 是泛型的标识符,一般是单个大写字母
 * 泛型的标识符可以有多个
 */
@SuppressWarnings({"all"})
class Tiger<T,R,M> {
    String name;
    T t;  // 属性使用到了泛型
    R r;
    M m;
    // 构造器使用泛型
    public Tiger(String name, T t, R r, M m) {
        this.name = name;
        this.t = t;
        this.r = r;
        this.m = m;
    }
    // 返回类型使用泛型
    public T getT() {
        return t;
    }
    // 方法使用泛型
    public void setT(T t) {
        this.t = t;
    }
    // 不允许这样实例化
    // 因为数组在new ,无法再内存开空间
//    T[] ts = new T[8];
    // 静态方法不允许使用泛型
    // 静态和类相关,在类加载时,对象还没有创建
    // 所以静态方法和静态属性使用了泛型,JVM就无法完成初始化
//    static R r1;
//    public static void m1(M m){}
}
自定义泛型接口
基本语法
interface 接口名<T,R...>{
}
注意细节
- 1.接口中,静态成员也不能使用泛型
 - 2.泛型的接口类型,在继承接口或者实现接口时确定
 - 3.没有指定类型,默认为Object
 
自定义泛型方法
基本语法
修饰符<T,R...> 返回类型 方法名(参数列表){
}
注意细节:
- 泛型方法,可以定义在普通类当中
 - 当泛型方法被调用时,类型会确定
 public void eat(E e){},该方法不是泛型方法,修饰符后没有<T,R...>,所以他只是使用了泛型
package javaSEStudy.generic.customGeneric;
// 泛型方法
public class CustomMethod {
    public static void main(String[] args) {
        Car car = new Car();
        // 当调用方法时,传入参数,编译器就会确定类型
        car.fly("宝马",1000);
    }
}
class Car {
    // 普通方法
    public void run() {
    }
    // 泛型方法
    public <T, R> void fly(T t, R r) {
    }
}
// 泛型类
class Fish<T, R> {
    /**
     * 泛型方法可以使用类声明的泛型,也可以使用自己声明的泛型
     */
    public <K> void hello (K k,R r) {
        
    }
    // 普通方法
    public void run(){
    }
    // 泛型方法
    public <U,M> void fly(U u, M m) {
    }
    // 使用泛型的方法
    // 他不是泛型方法,只是使用了类声明的泛型
    public void hi(T t){
    }
}
泛型的继承和通配符
- 泛型不具备继承性
 - : 支持任意泛型类型
 - :支持A类以及A类的子类,规定了泛型的上限
 - :支持A类以及A类的父类,不限于直接父类,规定了泛型的下限
 
JUnit
存在意义
- 1.一个类中很多功能代码都需要测试,为了测试就需要写入到main方法中
 - 2.如果有多个功能代码测试,就需要来回注销,切换很麻烦
 - 3.如果可以直接运行一个方法,就方便很多,并且可以给出相关信息 ---> JUnit
 

一般使用的是5.4版本的,添加并运行成功是如下效果

练习

package javaSEStudy.generic.test;
import javaSEStudy.basics.OOP.demo07.A;
import org.junit.jupiter.api.Test;
import java.util.*;
// 泛型类
public class Test1 {
    public static void main(String[] args) {
        // 原始测试方法
//        Dao<User> dao = new Dao<>();
//        User u1 = new User("张三", 15, 1);
//        User u2 = new User("李四", 16, 3);
//        User u3 = new User("王五", 18, 5);
//        User u4 = new User("老六", 10, 2);
//        User u5 = new User("虎七", 57, 4);
//        User u6 = new User("老八秘制小汉堡", 35, 6);
//
//
//        dao.save("1", u1);
//        dao.save("2", u2);
//        dao.save("3", u3);
//        dao.save("4", u4);
//        dao.save("5", u5);
//        dao.save("6", u6);
//
//        System.out.println(dao.get("1"));
//
//        dao.update("5", u6);
//
//        dao.delete("6");
//
//        for (Map.Entry<String, User> entry : dao.entrySet())  {
//            System.out.println("ID:  " + entry.getKey()  + " | " + entry.getValue());
//        }
    }
    @Test
    public void test() {
        // 泛型 T 被指定为User
        Dao<User> dao = new Dao<>();
        dao.save("001", new User("jack", 12, 1));
        dao.save("002", new User("tom", 25, 2));
        dao.save("003", new User("lucy", 19, 3));
        System.out.println(dao.list());
        System.out.println(dao.get("002"));
        dao.update("003", new User("Marry", 18, 3));
        dao.delete("002");
        System.out.println("---------------------------------");
        System.out.println(dao.list());
    }
}
class Dao<T> implements Iterable<T> {
    private Map<String, T> map = new HashMap<>();
    // 保存T类型的对象到Map中
    public void save(String id, T entity) {
        map.put(id, entity);
    }
    // 从map中获取对应id的对象
    public T get(String id) {
        return map.get(id);
    }
    // 替换map中所有key为id的内容,改为entity对象
    public void update(String id, T entity) {
        map.put(id, entity);
    }
    // 删除指定id的对象
    public void delete(String id) {
        map.remove(id);
    }
    // 返回map中存放的所有T对象
    public Set<Map.Entry<String, T>> entrySet() {
        return map.entrySet();
    }
    // 返回map中存放的T对象(老韩)
    // 遍历[k,v],将map的所有value(T entity),封装到ArrayList中即可
    public List<T> list() {
        // 创建一个ArrayList
        ArrayList<T> list = new ArrayList<>();
        // 遍历map
        Set<String> set = map.keySet();
        for (String o : set) {
            list.add(get(o));
        }
        return list;
    }
    @Override
    public Iterator<T> iterator() {
        return map.values().iterator();
    }
}
class User {
    private String name;
    private int age;
    private int id;
    public User(String name, int age, int id) {
        this.name = name;
        this.age = age;
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    @Override
    public String toString() {
        return "\nname='" + name + '\'' +
                ", age=" + age +
                ", id=" + id;
    }
}
                    
                
                
            
        
浙公网安备 33010602011771号