声明:以下笔记来源于韩顺平视频https://www.bilibili.com/video/BV1fh411y7R8?p=1,笔记为楼主亲手劳动,劳动不易,转载请标明谢谢。
泛型 (generic)
泛型的介绍
- 泛(广泛)型(类型) => Integer, String,Dog.
- 泛型又称参数化类型,是Jdk5.0出现的新特性,解决数据类型的安全性问题
- 在类声明或实例化时只要指定好需要的具体的类型即可。
- Java泛型可以
保证如果程序在编译时没有发出警告
,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮- 泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的
返回值
的类型,或者是参数
类型。- 特别强调: E具体的数 据类型在定义Person对象的时候指定,即在
编译期间
,就确定E是什么类型
泛型的理解与好处
在不使用泛型时
不能对加入到集合ArrayList中的数据类型进行约束(不安全),在预编译时不提示类型错误
遍历的时候,需要进行
类型转换
,如果集合中的数据量较大,对效率有影响。使用泛型时
- 编译时,检查添加元素的类型,提高了安全性
- 减少了类型转换的次数,提高效率
- 不在提示编译警告
泛型的语法
泛型的声明
- interface接口{}和class类<K,V,M>{}
//比如: List , ArrayList- 其中,T,K,V不代表值,而是表示类型。任意字母都可以。常用T表示,是Type的缩写
泛型的实例化
List<String> strList = new ArrayList <String> (); Iterator<Customer> iterator = customers.iterator();
@SuppressWarnings({"all"}) public class GenericExercise { public static void main(String[] args) { System.out.println("===========HashSet泛型==========="); HashSet<Student> students = new HashSet<Student>(); students.add(new Student("jack",18)); students.add(new Student("Tom",28)); students.add(new Student("Mary",19)); //遍历 for (Student student :students) { System.out.println(student); } System.out.println("===========HashMap泛型==========="); HashMap<String,Student> students1 = new HashMap<String,Student>(); students1.put("jack",new Student("jack",18)); students1.put("Tom",new Student("Tom",28)); students1.put("Mary",new Student("Mary",19)); Set<Map.Entry<String, Student>> entries = students1.entrySet(); Iterator<Map.Entry<String, Student>> iterator = entries.iterator(); while (iterator.hasNext()) { Map.Entry<String, Student> next = iterator.next(); System.out.println(next.getKey() + "-" + next.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 只能是引用类型
List <Integer> list = new ArrayList <Integer> ();//正确 List<int> list2 = new ArrayList<int> ();//错误
在指定泛型具体类型后,可以传入
该类型或者其子类类型
Pig<A> aPig = new Pig<A>(new A()); Pig<A> aPig = new Pig<A>(new B()); class A{} class B extend A{}
泛型使用形式
List<Integer> list1 = new ArrayList< Integer> ); List< Integer> list2 = new ArrayList<>();//推荐使用
如果我们这样写List list3 = new ArrayList(); 默认给它的泛型是[ E就是Object ]
ArrayList arrayList = new ArrayList(); //等价于 ArrayList<Object> arrayList = new ArrayList<>();
泛型练习题
要求:
- 该类包含: private成员变量name,sal,birthday,其中birthday为MyDate类的对象;
- 为每一个属性定义getter, setter方法;
- 重写toString方法输出name, sal, birthday
- MyDate类包含: private成员变量month,day,year;并为每一个属性定义 getter,setter方法;
- 创建该类的3个对象,并把这些对象放入ArrayList集合中(ArrayList 需使用泛型来定义),对集合中的元素进行排序,并遍历输出:
- 没基础的先自己想一遍最好。
@SuppressWarnings({"all"}) public 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 "MyDate_{" + "year=" + year + ", month=" + month + ", day=" + day + '}'; } @Override public int compareTo(MyDate_ o) {//面向对象复用法 //如果name相同就比较年。 int yearMinus = year - o.getYear(); if (yearMinus != 0) { return yearMinus; } //如果name相同就比较月。 int monthMinus = month - o.getMonth(); if (monthMinus != 0) { return monthMinus; } //如果name相同就比较日。 return day - o.getDay(); } }
@SuppressWarnings({"all"}) public class Employee_ { private String name; private double sal; private MyDate_ birthday; public Employee_(String name, double sal, MyDate_ birthday) { this.name = name; this.sal = sal; this.birthday = birthday; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getSal() { return sal; } public void setSal(double sal) { this.sal = sal; } public MyDate_ getBirthday() { return birthday; } public void setBirthday(MyDate_ birthday) { this.birthday = birthday; } @Override public String toString() { return "\nEmployee_{" + "name='" + name + '\'' + ", sal=" + sal + ", birthday=" + birthday + '}'; } }
@SuppressWarnings({"all"}) public class GenericExercise02 { public static void main(String[] args) { ArrayList<Employee_> employee_s = new ArrayList<>(); employee_s.add(new Employee_("tom",20000,new MyDate_(2000,11,11))); employee_s.add(new Employee_("jack",12000,new MyDate_(2000,12,12))); employee_s.add(new Employee_("tom",50000,new MyDate_(1980,10,10))); System.out.println(employee_s); System.out.println("====对雇员进行排序===="); employee_s.sort(new Comparator<Employee_>() { @Override public int compare(Employee_ emp1, Employee_ emp2) { //先对传入的参数进行验证 if (!(emp1 instanceof Employee_ && emp2 instanceof Employee_)) { System.out.println("类型不匹配!"); return 0; } //比较name int i = emp1.getName().compareTo(emp2.getName()); if (i != 0) { return i; } return emp1.getBirthday().compareTo(emp2.getBirthday()); } }); System.out.println(employee_s); } }
自定义泛型类
基本语法
class/interface 类名/接口名 <T,R,M,…> {
成员
}
使用细节
- 普通成员可以使用泛型(属性、方法)—>(构造器,getter与setter方法)
- 使用泛型的数组,不能初始化(因为
数组在new不能确定T的类型,就无法在内存开空间
)静态方法,静态属性中不能使用类的泛型
- 泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
- 如果在创建对象时,
没有指定类型,默认为Object
- T, R, M泛型的标识符,
一般是单个大写字母
自定义泛型类
@SuppressWarnings({"all"}) public class CustorGeneric_ <T, R, M>{ String name; T t; R r; M m; //使用泛型的数组,不能初始化(因为数组在new不能确定T的类型,就无法在内存开空间) // M[] mm = new M[8]; //静态方法,静态属性中不能使用类的泛型 // static T tt; // public static void m1(M m){} public CustorGeneric_(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; } public R getR() { return r; } public void setR(R r) { this.r = r; } public M getM() { return m; } public void setM(M m) { this.m = m; } }
自定义泛型接口
基本语法
interface接口名<T, R…> {}
使用细节
- 接口中,静态成员也不能使用泛型(这个和泛型类规定一样)
- 泛型接口的类型,在
继承接口
或者实现接口
时确定- 没有指定类型,
默认为Object
自定义接口
@SuppressWarnings({"all"}) public class CustorInterfaceGeneric_ { } class CC implements IUsb {//不指定参数类型默认为default @Override public Object get(Object o) { return null; } @Override public void hi(Object o) { } @Override public void run(Object r1, Object r2, Object u1, Object u2) { } } interface BB extends IUsb<String,Integer> {} class AA implements IUsb<String, Integer> { @Override public Integer get(String s) { return null; } @Override public void hi(Integer integer) { } @Override public void run(Integer r1, Integer r2, String u1, String u2) { } } interface IUsb<U, R> { //接口的参数是 public static final // U n = 10; R get(U u); void hi(R r); void run(R r1, R r2, U u1, U u2); default R method(U u) { return null; } }
自定义泛型方法
基本语法
修饰符<T,R… >返回类型方法名(参数列表) {
}注意细节
- 泛型方法,可以定义在普通类中,也可以定义在泛型类中
- 当泛型方法被调用时,类型会确定
- public void eat(E e) {},修饰符后没有<T,R…> eat方法不是泛型方法,而是使用了泛型
- 当调用方法时,传入参数,编译器,就会确定类型
- 泛型方法,可以使用类声明的泛型,也可以使用自己声明泛型
自定义泛型接口
@SuppressWarnings({"all"}) public class CustorMethodGeneric_ { public static void main(String[] args) { Car car = new Car(); car.fly("宝马",100);//当调用方法时,传入参数,编译器,就会确定类型 System.out.println("==============="); fish<String, ArrayList> fish = new fish<>(); fish.hello(new ArrayList(),13.3f); } } //泛型方法,可以定义在普通类中,也可以定义在泛型类中 class Car { public void run() {}//普通方法 public <T, R> void fly(T t,R r) {//泛型方法 System.out.println(t.getClass()); System.out.println(r.getClass()); } } class fish<T, R>{ public void run() {}//普通方法 public <U, M> void fly(U u,M m) {}//泛型方法 public void hi(T t1) {//使用了泛型,并非泛型方法 } //泛型方法,可以使用类声明的泛型,也可以使用自己声明泛型 public<K> void hello(R r, K k){ System.out.println(k.getClass()); System.out.println(r.getClass()); } }
泛型的类型及通配符
泛型
不具有继承性
Object obj = new String("xx");//可以 // 泛型没有继承性 // ArrayList<Object> strings = new ArrayList<String>();
- <?> :`支持任意泛型类型`
- <? extends A>:支持A类以及A类的子类,`规定了泛型的上限`
- <? super A>:支持A类以及A类的父类,不限于直接父类,`规定了泛型的下限`
@SuppressWarnings({"all"}) public class GenericExtends_ { public static void main(String[] args) { Object obj = new String("xx");//可以 // 泛型没有继承性 // ArrayList<Object> strings = new ArrayList<String>(); ArrayList<Object> l1 = new ArrayList<>(); ArrayList<String> l2 = new ArrayList<>(); ArrayList<AA> l3 = new ArrayList<>(); ArrayList<BB> l4 = new ArrayList<>(); ArrayList<CC> l5 = new ArrayList<>(); // public static void printCollection1(List<?> c) //? 表示可以接收任意类型 printCollection1(l1);//√ printCollection1(l2);//√ printCollection1(l3);//√ printCollection1(l4);//√ printCollection1(l5);//√ //public static void printCollection2(List<? extends AA> c) //? extends AA 表示可以接收AA或其子类 // printCollection2(l1);//√ // printCollection2(l2);//√ printCollection2(l3);//√ printCollection2(l4);//√ printCollection2(l5);//√ //public static void printCollection3(List<? super AA> c) //? super AA 表示可以接收AA或父类 ,不限于直接父类 printCollection3(l1);//√ // printCollection3(l2);//√ printCollection3(l3);//√ // printCollection3(l4);//√ // printCollection3(l5);//√ } //? 表示可以接收任意类型 public static void printCollection1(List<?> c) { for (Object o : c) { System.out.println(o); } } //? extends AA 表示可以接收AA或其子类 public static void printCollection2(List<? extends AA> c) { for (Object o : c) { System.out.println(o); } } //? super AA 表示可以接收AA或父类 ,不限于直接父类 public static void printCollection3(List<? super AA> c) { for (Object o : c) { System.out.println(o); } } } class AA{} class BB extends AA{} class CC extends BB{}
JUnit 单元测试类
- JUnit是一个Java语言的单元测试框架
- 多数Java的开发环境都已经集成了JUnit作为单元测试的工具