泛型
泛型
使用传统方法问题解析
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号