泛型介绍:
- 泛型又称参数化类型,是JDK5.0出现的新特性,解决数据类型的安全性问题。
- 在类声明或者实例化时,只需要指定好需要的具体类型即可。
- Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCaseException异常,同时代码更加简洁,健壮。
- 泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值类型,又或者是参数类型。
(这个具体演示代码如下)
public class Generic03 { public static void main(String[] args) { Person<String> person = new Person<String>("张三"); System.out.println(person.getS()); person.show(); Person<Integer> integerPerson = new Person<Integer>(20); System.out.println(integerPerson.getS()); integerPerson.show(); } } class Person<E> { E s; public Person(E s) { this.s = s; } public E getS() { return s; } public void show() { System.out.println(s.getClass()); } }
输出结果如下:
张三 class java.lang.String 20 class java.lang.Integer
下面是Java泛型的应用实例:
public class GenericExercise { public static void main(String[] args) { Student student1 = new Student("张三", 18); Student student2 = new Student("小明", 18); Student student3 = new Student("阿黄", 18); //使用泛型方式给HashMap,放入3个学生对象 /* public class HashMap<K,V> */ //k->String //V->Student HashMap<String, Student> stringStudentHashMap = new HashMap<>(); stringStudentHashMap.put("1", student1); stringStudentHashMap.put("2", student2); stringStudentHashMap.put("3", student3); Set<String> strings = stringStudentHashMap.keySet(); //迭代器 Iterator<String> iterator = strings.iterator(); while (iterator.hasNext()) { Student student = stringStudentHashMap.get(iterator.next()); System.out.println(student.getAge() + "-" + student.getName()); } HashSet<Student> students = new HashSet<>(); students.add(new Student("JACK", 18)); students.add(new Student("Tom", 18)); students.add(new Student("Maria", 18)); for (Student student : students) { System.out.println(student.getName() + "-" + student.getAge()); } } } 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; } }
运行结果:
18-张三 18-小明 18-阿黄 Maria-18 JACK-18 Tom-18
泛型的使用细节如下:
public class GenericDetail01 { public static void main(String[] args) { //1.给泛型指向数据类型时,要求是引用类型,不能是基本数据类型。 ArrayList<Integer> list4 = new ArrayList<>(); //ok // ArrayList<int> list5 = new ArrayList<>(); //错误 // ArrayList<A> as = new ArrayList<>(); //2.因为E(泛型) 指定了A类型,构造器传入了new A() //在给泛型指定具体类型后,可以传入该类型或者其子类型。 Pig<A> aPig = new Pig<A>(new A()); aPig.f(); //输出: class generic.improve.A Pig<A> aPig1 = new Pig<A>(new B()); aPig1.f(); //输出:class generic.improve.B //3.泛型的使用形式 List<Integer> list1 = new ArrayList<Integer>(); ArrayList<Integer> list2 = new ArrayList<Integer>(); //在实际开发中,我们往往简写 //编译器会进行类型推断,推荐的写法 List<Integer> list3 = new ArrayList<>(); List<Integer> list10 = new ArrayList<>(); //4.如果是这样写的话,泛型默认是Object ArrayList list = new ArrayList();//等价ArrayList<Object> list = new ArrayList<Object>(); Tiger tiger = new Tiger(); //相当于如下 /* class Tiger{//类 Object e; public Tiger() { } public Tiger(Object e) { this.e = e; } } */ } } class Tiger<E> { E e; public Tiger() { } public Tiger(E e) { this.e = e; } } class A { } class B extends A { } class Pig<E> { E s; public Pig(E s) { this.s = s; } public void f() { System.out.println(s.getClass()); } }
泛型的练习要求如下:
实现步骤如下:
一、首先创建MyDate类
public class MyDate { private int month; private int day; private int year; public MyDate(int year, int month, int day) { this.month = month; this.day = day; 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; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } @Override public String toString() { return "MyDate{" + "month=" + month + ", day=" + day + ", year=" + year + '}'; } }
二、创建Employee类
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 "Employee{" + "name='" + name + '\'' + ", sal=" + sal + ", birthday=" + birthday + '}'; } }
三、实现类GenericExercise02代码如下:
public class GenericExercise02 { public static void main(String[] args) { MyDate myDate1 = new MyDate(1980, 11, 11); MyDate myDate2 = new MyDate(2001, 12, 12); MyDate myDate3 = new MyDate(1980, 11, 10); Employee employee1 = new Employee("tom", 20000, myDate1); Employee employee2 = new Employee("aa小明", 12000, myDate2); Employee employee3 = new Employee("tom", 50000, myDate3); ArrayList<Employee> employees = new ArrayList<>(); employees.add(employee1); employees.add(employee2); employees.add(employee3); employees.sort(new Comparator<Employee>() { @Override public int compare(Employee o1, Employee o2) { //先按照name排序,如果name相同,则按照生日日期的先后顺序,【即:定制排序】 //先对传入的参数进行验证 if (!(o1 instanceof Employee && o2 instanceof Employee)) { System.out.println("类型不正确!"); return 0; //表示不比了,返回0就行了 } //比较name String name1 = o1.getName(); String name2 = o2.getName(); int i = name1.compareTo(name2); if (i != 0) { //说明名字不相同 return i; //按名字的升序排列 加-号 则是降序,或者改为int i = name2.compareTo(name1); } //下面是对birthday的比较,因此我们最好把这个比较,放在MyDate中完成 //如果姓名相同 按照生日先后顺序排序 MyDate birthday1 = o1.getBirthday(); MyDate birthday2 = o2.getBirthday(); int yearMinus = birthday1.getYear() - birthday2.getYear(); if (yearMinus != 0) { return yearMinus; } //如果year相同,就比较month int monthMinus = birthday1.getMonth() - birthday2.getMonth(); if (monthMinus != 0) { return monthMinus; } //如果year和month 都相同 比较日 return birthday1.getDay() - birthday2.getDay(); } }); System.out.println("==对雇员进行排序后"); for (int i = 0; i < employees.size(); i++) { Employee employee = employees.get(i); System.out.println(employee); } } }
优化:
对birthday生日日期的比较,我们最好把这个比较,放在MyDate中完成。
具体实现如下:
一、修改MyDate类
public class MyDate implements Comparable<MyDate>{ private int month; private int day; private int year; public MyDate(int year, int month, int day) { this.month = month; this.day = day; 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; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } @Override public String toString() { return "MyDate{" + "month=" + month + ", day=" + day + ", year=" + year + '}'; } @Override public int compareTo(MyDate o) {//把对year-month-day比较放在这里 int yearMinus = year - o.getYear(); if (yearMinus != 0) { return yearMinus; } //如果year相同,就比较month int monthMinus = month - o.getMonth(); if (monthMinus != 0) { return monthMinus; } //如果year和month 都相同 比较日 return day - o.getDay(); } }
之后再修改GenericExercise02类如下:
public class GenericExercise02 { public static void main(String[] args) { MyDate myDate1 = new MyDate(1980, 11, 11); MyDate myDate2 = new MyDate(2001, 12, 12); MyDate myDate3 = new MyDate(1980, 11, 10); Employee employee1 = new Employee("tom", 20000, myDate1); Employee employee2 = new Employee("aa小明", 12000, myDate2); Employee employee3 = new Employee("tom", 50000, myDate3); ArrayList<Employee> employees = new ArrayList<>(); employees.add(employee1); employees.add(employee2); employees.add(employee3); employees.sort(new Comparator<Employee>() { @Override public int compare(Employee o1, Employee o2) { //先按照name排序,如果name相同,则按照生日日期的先后顺序,【即:定制排序】 //先对传入的参数进行验证 if (!(o1 instanceof Employee && o2 instanceof Employee)) { System.out.println("类型不正确!"); return 0; //表示不比了,返回0就行了 } //比较name String name1 = o1.getName(); String name2 = o2.getName(); int i = name1.compareTo(name2); if (i != 0) { //说明名字不相同 return i; //按名字的升序排列 加-号 则是降序,或者改为int i = name2.compareTo(name1); } //下面是对birthday的比较,因此我们最好把这个比较,放在MyDate中完成 //封装后,将来的可维护性和复用性,就大大增强。 return o1.getBirthday().compareTo(o2.getBirthday()); } }); System.out.println("==对雇员进行排序后"); for (int i = 0; i < employees.size(); i++) { Employee employee = employees.get(i); System.out.println(employee); } } }
自定义泛型类:
@SuppressWarnings("all") public class CustomGeneric_ { public static void main(String[] args) { Tiger<Double, String, Integer> tiger = new Tiger<Double, String, Integer>("TOM"); tiger.setT(10.9);//OK // tiger.setT("sdf");//错误 Tiger tiger1 = new Tiger("john~"); tiger1.setT("yy"); } } class Tiger<T, R, M> { String name; R r; M m; T t; //因为数组在new的时候,不能确定类型。 T[] ts; // public static void m1(M m){} public Tiger(String name) { this.name = name; } public Tiger(R r, M m, T t) { this.r = r; this.m = m; this.t = t; } public Tiger(String name, R r, M m, T t) { this.name = name; this.r = r; this.m = m; this.t = t; } public String getName() { return name; } public void setName(String name) { this.name = name; } 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; } public T getT() { return t; } public void setT(T t) { this.t = t; } }
自定义泛型接口:
public class CustomGeneric02 { public static void main(String[] args) { Dog dog = new Dog(); dog.f(); } } /** * 泛型接口的使用说明: * 1.接口中,静态成员也不能使用泛型 * 2.泛型接口的类型,在继承接口或者实现接口时确定 * 3.没有指定类型,默认为Object */ class Dog implements testInter { public void f() { System.out.println(n); } } interface testInter { int n = 100; } interface IA extends IUsb<String, Double> { } //当我们去实现IA接口时,因为IA在继承IUsb接口时,指定了U 为String R 为Double //在实现IUsb接口的方法时,使用String替换U,Double替换R class AA implements IA { @Override public Double get(String s) { return null; } @Override public void hi(Double aDouble) { } @Override public void run(Double r1, Double r2, String u1, String u2) { } } /** * 实现接口时,直接指定泛型接口的类型 * 给U 指定Integer,给R指定Float * 所以,当我们实现IUsb方法时,会使用Integer替换U,使用Float替换R */ class BB implements IUsb<Integer, Float> { @Override public Float get(Integer integer) { return null; } @Override public void hi(Float aFloat) { } @Override public void run(Float r1, Float r2, Integer u1, Integer u2) { } } //没有指定类型,默认为Object //建议直接写成:IUsb<Object,Object> class CC implements IUsb<Object, Object> {//等价class CC implements IUsb<Object,Object> @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 IUsb<U, R> { // U name; //不能这样使用 int 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; } }
自定义泛型方法:
public class CustomMethodGeneric { public static void main(String[] args) { Car car = new Car(); car.fly("宝马", 100);//当调用方法时,传入参数,编译器就会确定类型 Fish<String, ArrayList> fish = new Fish<>(); fish.hello(new ArrayList(), 10f); } } //泛型方法,可以定义在普通类中,也可以定义在泛型类中 class Car { //普通类 public void run() { } //说明 //1.<T,R> 就是泛型 //2.是提供给fly使用的 public <T, R> void fly(T t, R r) {//泛型方法 System.out.println(t.getClass());//class java.lang.String System.out.println(r.getClass());//class java.lang.Integer } } class Fish<T, R> {//泛型类 public void run() {//普通方法 } public <U, M> void eat(U u, M m) {//泛型方法 } //说明 //1.下面的hi()方法不是泛型方法 //2.是hi()方法使用了类声明的泛型 public void hi(T t) { } //泛型方法,可以使用类声明的泛型,也可以使用自己声明的泛型 public <K> void hello(R r, K k) { System.out.println(r.getClass());//class java.util.ArrayList System.out.println(k.getClass());//class java.lang.Float } }
泛型的继承和通配符
/** * 泛型的继承和通配符 */ public class GenericExtends { public static void main(String[] args) { Object oo = new String(); //泛型没有继承性 // List<Object> list=new ArrayList<String>();//错误 ArrayList<Object> list1 = new ArrayList<>(); ArrayList<String> list2 = new ArrayList<>(); ArrayList<AA> list3 = new ArrayList<>(); ArrayList<BB> list4 = new ArrayList<>(); ArrayList<CC> list5 = new ArrayList<>(); //如果是List<?> c 可以接受任意的泛型类型 printCollection1(list1); printCollection1(list2); printCollection1(list3); printCollection1(list4); printCollection1(list5); //List<? extends AA> c ,可以接受AA 或者AA子类 // printCollection2(list1); //x // printCollection2(list2); //x printCollection2(list3); printCollection2(list4); printCollection2(list5); //List<? super AA> c 支持AA类以及AA类的父类,不限于直接父类 printCollection3(list1); //√ // printCollection3(list2); //× printCollection3(list3);//√ // printCollection3(list4);//× // printCollection3(list5);//× } //说明:List<?> 表示任意的泛型类型都可以接受 public static void printCollection1(List<?> c) { for (Object object : c) {//通配符取出时,就是Object System.out.println(object); } } //? extends AA 表示上限,可以接受AA 或者AA子类 public static void printCollection2(List<? extends AA> c) { for (Object object : c) { System.out.println(object); } } //? super 子类类名AA :支持AA类以及AA类的父类,不限于直接父类 //规定了泛型的下限 public static void printCollection3(List<? super AA> c) { for (Object object : c) { System.out.println(object); } } } class AA { } class BB extends AA { } class CC extends BB { }
