今天学习的内容是泛型
一、泛型的意义
泛型意味着“类型安全”,它实现了参数化类型的概念。实际上泛型就是将运行时可能发生的问题放到编译期解决。比如:在泛型出现之前,任意类型的引用都可以存储进集合,并被向上转型为Object类型,取出的引用仍旧是Object类型,如果想要操作它就必须对其进行强制类型转换,这就存在了安全隐患!这是由于集合中可能存在不同类型的引用,强制转换就可能会发生ClassCastException。但如果使用泛型,编译器就知道集合中存储的一定是泛型类型或其子类/实现类的引用(多态与泛型并不冲突),并被向上转型为泛型类型,取出的一定是该泛型类型的引用,这时候就不用再对其进行强制类型转换,解决了类型安全问题。其实这么做就相当于将类型参数化:此集合只存储此类型或其子类/实现类的引用,不接收其他类型的引用。程序示例:
public class Test70 {
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void main(String[] args) {
// 不使用泛型,会有安全隐患
ArrayList list_1 = new ArrayList();
list_1.add("a");// String类型的对象
list_1.add(1);// Integer类型的对象
Iterator it_1 = list_1.iterator();
while (it_1.hasNext()) {
try {
String str = (String) it_1.next();// ClassCastException
System.out.println(str);
} catch (ClassCastException e) {
e.printStackTrace();
}
}
// 如果使用泛型,可以避免安全隐患
ArrayList<String> list_2 = new ArrayList<>();
list_2.add("a");
// !list_2.add(1);
Iterator<String> it_2 = list_2.iterator();
while(it_2.hasNext()){
String str = it_2.next();
System.out.println(str);
}
}
}
注意:编译器生成的字节码文件中是不带有泛型的,这个称为泛型的擦除,这么做的目的主要是为了兼容JDK1.4的类加载器。相应的,JVM在运行时可以通过获取元素的类型,自动进行类型转换动作,这成为泛型的补偿。
二、自定义泛型
泛型使用最多的就是在集合类中,不过我们也可以自定义泛型。比如当类中要操作的引用类型不确定时,可以自定义泛型类;当方法中要操作的引用的类型不确定时,可以自定义泛型方法;除此之外,也可以自定义泛型接口。示例程序:
public class Test72 {
public static void main(String[] args) {
// 使用自定义泛型类
Tool<String> tool_str = new Tool<>();
Tool<Integer> tool_int = new Tool<>();
tool_str.setTool("a");
tool_int.setTool(1);
tool_str.print("b");// b
// ! tool_str.print(2); 如果方法使用的是类定义的泛型,必须按照类定义的泛型传参
tool_int.print(2);// 2
// ! tool_int.print("b"); 如果方法使用的是类定义的泛型,必须按照类定义的泛型传参
System.out.println(tool_str.getTool());// a
System.out.println(tool_int.getTool());// 1
// 使用自定义泛型方法,可以传入任何参数
tool_str.myPrint("a");// a
tool_str.myPrint(1);// 1
tool_int.myPrint("a");// a
tool_int.myPrint(1);// 1
Tool.myShow("a");// a
Tool.myShow(1);// 1
}
}
// 自定义泛型类,使用场景:当类中要操作的引用的类型不确定时
class Tool<T> {
private T tool;
public T getTool() {
return tool;
}
public void setTool(T tool) {
this.tool = tool;
}
public void print(T tool) {
System.out.println(tool);
}
// 自定义泛型方法,使用场景:当方法中要操作的引用的类型不确定时
public <E> void myPrint(E e) {
System.out.println(e);
}
// 注意静态方法只能自定义泛型,不能使用类定义的泛型
public static <E> void myShow(E a) {
System.out.println(a);
}
}
//自定义泛型接口
interface Inter<T>{
void show(T t);
<E> void myShow(E e);
}
class InterImpl_1 implements Inter<String>{
@Override
public void show(String t) {
}
@Override
public <E> void myShow(E e) {
}
}
class Interimpl_2<T> implements Inter<T>{
@Override
public void show(T t) {
}
@Override
public <E> void myShow(E e) {
}
}
三、泛型与集合
之前学习多态时,我们知道泛型参数不支持多态,也就是List<Fu> list = new ArrayList<Zi>();是不被允许的;同理,如果方法的参数是List<Fu>类型,ArrayList<Zi>也不能作为参数传入方法。这主要是出于安全考虑,因为在方法内部有可能把另一个子类参数的引用存储进集合,这就会出现错误!这种问题的解决方法有两种:
- 修饰符 <T> 返回值类型 方法名(Collection<T> c){} 或者修饰符 <T extends X> 返回值类型 方法名(Collection<T> c){}
- 方法名(Collection<?> c){} 、方法名(Collection<? extends X> c){}或方法名(Collection<? super X> c){}
public class Test71 {
public static void main(String[] args) {
// 泛型基本用法,使用String类集合
ArrayList<String> al_1 = new ArrayList<>();
al_1.add("a");
al_1.add("s");
al_1.add("fd");
al_1.add("gsd");
System.out.println("--------------泛型基本用法,使用String类集合----------------");
printCollection_1(al_1);
printCollection_2(al_1);
// !printCollection_3(al_1);
// !printCollection_4(al_1);
// !printCollection_5(al_1);
//!printCollection_6(al_1);
// 泛型基本用法,使用Person类集合
TreeSet<Person> ts = new TreeSet<>();// 也可以使用比较器排序
ts.add(new Person("sf", 27));
ts.add(new Person("fab", 21));
ts.add(new Person("xc", 24));
ts.add(new Person("popo", 23));
System.out.println("\n\n--------------泛型基本用法,使用Person类集合----------------");
printCollection_1(ts);
printCollection_2(ts);
printCollection_3(ts);
printCollection_4(ts);
printCollection_5(ts);
printCollection_6(ts);
// 向上限定的用法
ArrayList<Student> al_2 = new ArrayList<>();
al_2.add(new Student("a", 13));
al_2.add(new Student("asfda", 12));
al_2.add(new Student("asdf", 13));
al_2.add(new Student("fda", 11));
System.out.println("\n\n--------------向上限定的用法----------------");
printCollection_1(al_2);
printCollection_2(al_2);
// !printCollection_3(al_2);
printCollection_4(al_2);
printCollection_5(al_2);
//!printCollection_6(al_2);
// 向下限定的用法
ArrayList<Organism> al_3 = new ArrayList<>();
al_3.add(new Organism());
al_3.add(new Organism());
al_3.add(new Organism());
al_3.add(new Organism());
System.out.println("\n\n--------------向下限定的用法----------------");
printCollection_1(al_3);
printCollection_2(al_3);
//!printCollection_3(al_3);
//!printCollection_4(al_3);
//!printCollection_5(al_3);
printCollection_6(al_3);
}
// 使用自定义泛型(可以接收存储任何对象的集合)
public static <T> void printCollection_1(Collection<T> ts) {
System.out.println("使用自定义泛型:");
// !ts.add(new Worker("k", 12));
//ts.clear();只能获取或删除,不能添加
Iterator<T> it = ts.iterator();
while (it.hasNext()) {
T t = it.next();
System.out.print(t);
}
}
// 使用类型通配符(可以接收存储任何对象的集合)
public static void printCollection_2(Collection<?> ts) {
System.out.println("\n使用类型通配符:");
// !ts.add(new Worker("k", 12));
//ts.clear();只能获取或删除,不能添加
Iterator<?> it = ts.iterator();
while (it.hasNext()) {
System.out.print(it.next());
}
}
// 使用确定类型(只能接收存储Person对象的集合)
public static void printCollection_3(Collection<Person> ts) {
System.out.println("\n使用确定泛型:");
ts.add(new Worker("k", 12));// 如果能传入Student的集合,这里就会出现错误的!所以编译不会通过!
Iterator<Person> it = ts.iterator();
while (it.hasNext()) {
Person p = it.next();
System.out.print(p);
}
}
// 向上限定,使用自定义泛型(只能接收存储Person对象、Person子类对象或Person实现类的集合)
public static <T extends Person> void printCollection_4(Collection<T> ts) {
System.out.println("\n向上限定,使用自定义泛型:");
// !ts.add(new Worker("k", 12));
//ts.clear();只能获取或删除,不能添加
Iterator<T> it = ts.iterator();
while (it.hasNext()) {
Person p = it.next();
System.out.print(p);
}
}
// 向上限定,使用类型通配符(只能接收存储Person对象、Person子类对象或Person实现类对象的集合)
public static void printCollection_5(Collection<? extends Person> ts) {
System.out.println("\n向上限定,使用类型通配符:");
// !ts.add(new Worker("k", 12));
//ts.clear();只能获取或删除,不能添加
Iterator<? extends Person> it = ts.iterator();
while (it.hasNext()) {
Person p = it.next();
System.out.print(p);
}
}
// 向下限定,不能使用自定义泛型
// 向下限定,使用类型通配符(只能接收存储Person对象或Person父类对象的集合)
public static void printCollection_6(Collection<? super Person> ts) {
System.out.println("\n向下限定,使用类型通配符:");
// !ts.add(new Worker("k", 12));
//ts.clear();只能获取或删除,不能添加
Iterator<? super Person> it = ts.iterator();
while (it.hasNext()) {
System.out.print(it.next());
}
}
}
class Organism{
@Override
public String toString() {
return "Organism []";
}
}
class Person extends Organism implements Comparable<Person> {
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
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 int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Person o) {
int temp = this.age - o.age;
return temp == 0 ? this.name.compareTo(o.name) : temp;
}
}
class Student extends Person {
public Student() {
super();
}
public Student(String name, int age) {
super(name, age);
}
@Override
public String toString() {
return "Student [name=" + getName() + ", age=" + getAge() + "]";
}
}
class Worker extends Person {
public Worker() {
super();
}
public Worker(String name, int age) {
super(name, age);
}
}
// 比较器
class ComparatorByName implements Comparator<Person> {
@Override
public int compare(Person o1, Person o2) {
int temp = o1.getName().compareTo(o2.getName());
return temp == 0 ? o1.getAge() - o2.getAge() : temp;
}
}