韩顺平Java33——泛型
泛型(generic)
一言以蔽之——泛型就是可以接受数据类型的数据类型
1.泛型的引出
- 传统方法:
package test; import java.util.ArrayList; /** * @author 紫英 * @version 1.0 */ public class Test { public static void main(String[] args) { ArrayList arrayList = new ArrayList(); arrayList.add(new Dog_("旺财",5)); arrayList.add(new Dog_("大黄",3));//遍历 for (Object o : arrayList) { //先向下转型 Dog_ d=(Dog_) o; System.out.println("名字" + d.getName() + "年龄:" + d.getAge()); } } } class Dog_ { String name; int age; @Override public String toString() { return "Dog_{" + "name='" + name + '\'' + ", 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; } public Dog_(String name, int age) { this.name = name; this.age = age; } } class Cat{ String name; int 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; } public Cat(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Cat{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
这时在遍历时我们必须向下转型而不能够直接写成Dog类型:
这个时候假如我们不小心添加了一只猫,编译时并不会报错,而是会在运行遍历时报以下异常:
//这时如果程序员不小心添加了一只猫 arrayList.add(new Cat("咪咪",2));
因为刚才在这里我们进行了向下转型,而Cat无法强转为Dog类型:
总结我们遇到的问题:
如果数据量大的话每次遍历都需要进行向下转型很麻烦,这时就可以引出泛型。
我们使用泛型再进行刚才的操作:
ArrayList<Dog_> arrayList = new ArrayList<>();
可以看到完美解决了之前的两个痛点,添加Cat实例时编译报错而且无需向下转型可以直接遍历(nice!)
2.泛型的好处
3.泛型介绍
比如这里Dog并不是泛型,而是泛型的类型(泛型可以理解为数据类型的类型),这个Dog会传递给那个E
注特别强调:E具体的数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
4.泛型语法
- 练习1:
package generic; import java.util.*; /** * @author 紫英 * @version 1.0 * @discription */ public class Generic02 { public static void main(String[] args) { Student jack = new Student("jack", 15); Student marry = new Student("marry", 14); Student tom = new Student("tom", 11); HashSet<Student> students = new HashSet<Student>(); /* public class HashMap<K,V> */ students.add(jack); students.add(marry); students.add(tom); for (Student student : students) { System.out.println(student); } HashMap<String, Student> stuMap = new HashMap<String, Student>(); stuMap.put("jack",jack); stuMap.put("marry",marry); stuMap.put("tom",tom); Set<String> keySet = stuMap.keySet(); for (String s : keySet) { System.out.println("name:" + s +" "+ "age:" + stuMap.get(s)); } System.out.println("=======迭代器遍历======="); Set<Map.Entry<String, Student>> entries = stuMap.entrySet(); /* public Set<Map.Entry<K,V>> entrySet() { Set<Map.Entry<K,V>> es; return (es = entrySet) == null ? (entrySet = new EntrySet()) : es; } */ Iterator<Map.Entry<String, Student>> iterator = entries.iterator(); /* public final Iterator<Map.Entry<K,V>> iterator() { return new EntryIterator(); } */ while (iterator.hasNext()) { Map.Entry<String, Student> m = iterator.next(); System.out.println("name:"+m.getKey()+" "+ "age:" + m.getValue()); } } } class Student{ public String name; public int age; @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } public Student(String name, int age) { this.name = name; this.age = age; } }
5.注意事项和使用细节
示例:
public class Generic03 { public static void main(String[] args) { HashSet<Animal> animals = new HashSet<>(); //在给泛型制定具体类型后可以传入该类型或其子类型 animals.add(new Pig<String>("pig")); HashSet<Pig> pigs = new HashSet<>(); //右边可以省略 } } class Animal{} class Pig <E>extends Animal{ E e; public Pig(E e) { this.e = e; } }
- 练习2
package generic; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Comparator; /** * @author 紫英 * @version 1.0 * @discription */ public class Generic04 { public static void main(String[] args) { Employee jack = new Employee("jack", 15000, new MyDate(2000, 12, 26)); Employee jack1 = new Employee("jack", 14000, new MyDate(2000, 12, 26)); Employee jack2 = new Employee("jack", 14000, new MyDate(1998, 11, 25)); // Employee jack3 = new Employee("jack", 14000, new MyDate(2010, 11, 26)); Employee marry = new Employee("marry", 16000, new MyDate(1999, 1, 4)); ArrayList<Employee> employees = new ArrayList<>(); employees.add(jack); employees.add(jack1); employees.add(jack2); employees.add(marry); employees.sort(new Comparator<Employee>() { @Override public int compare(Employee o1, Employee o2) { if (!(o1.getName().equals(o2.getName()))) { return o1.getName().compareTo(o2.getName()); } else { return o1.getBirthday().compareTo(o2.getBirthday()); } } }); for (Employee employee : employees) { System.out.println(employee); } } } class Employee { private String name; private double sal; private MyDate 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; } public Employee(String name, double sal, MyDate birthday) { this.name = name; this.sal = sal; this.birthday = birthday; } @Override public String toString() { return "Employee{" + "name='" + name + '\'' + ", sal=" + sal + ", 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 + "-" + month + "-" + day + '}'; } @Override public int compareTo(@NotNull MyDate date) { //中间变量存储传入的数据 int year1 = (date).getYear(); int yearMin = year - year1; int month1 = (date).getMonth(); int monthMin = month - month1; int day1 = (date).getDay(); int dayMin = day - day1; if (yearMin != 0) { return yearMin; } else if (monthMin != 0) { return monthMin; } else return dayMin; } }
6.自定义泛型
- 6.1自定义泛型类
说明:T、R等为泛型的标识符,一般为一个大写字母
泛型数组不能初始化是因为不知道要开辟多少空间的内存
静态方法和属性不能使用泛型是因为static是在类加载的时候就需要确定的,而泛型是在创建对象时才确定,先后顺序不一致(static先于泛型)
练习:这里Tiger类后面加了泛型我们称之为自定义泛型类
- 6.2自定义泛型接口
这里注意:接口中的方法和属性都是抽象,属性是public static final的,方法是public abstract的,所以不能定义泛型类型的属性。
- 6.3自定义泛型方法
- 小练习:
7.泛型的继承和通配符
1)错误,泛型之间不具有继承性(虽然String是Object的子类)
写法:
本文来自博客园,作者:紫英626,转载请注明原文链接:https://www.cnblogs.com/recorderM/p/15836591.html