- 初识泛型
- 了解泛型
- 泛型类
- 泛型方法
- 泛型接口(不常用)
- 泛型限定
#初识泛型
- 泛型是JDK1.5引入的新特性,用于解决类型安全问题
- 好处:编译时提前发现可能存在的类型转换异常;避免强制转换的麻烦
- 所谓泛型,就是变量类型的参数化
- API文档中,有<>尖括号的地方,就可以使用泛型
import java.util.TreeSet;
public class Test {
public static void main(String[] args) {
TreeSet<String> ts = new TreeSet<String>();
ts.add("1");
ts.add("2");
ts.add("3");
System.out.println(ts);
}
}
#了解泛型
ArrayList< E > 类定义和ArrayList< Integer > 类引用中涉及的术语
- 整个称为ArrayList< E >泛型类型
- ArrayList< E > 中的E称为类型变量或类型参数
- 整个ArrayList< Integer > 称为参数化的类型
- ArrayList< Integer > 中的Integer 称为类型参数的实例或实际类型参数
- ArrayList< Integer > 中的**<> 念着typeof**
- ArrayList 称为原始类型
- 参数化类型不考虑类型参数的继承;创建数组实例时,数组的元素不能使用参数化的类型
Vector<String> v = new Vector<Object>(); //错误
Vector<Object> v = new Vector<String>(); //也错误
Vector<Integer> vectorList[] = new Vector<Integer>[10];//错误
#泛型类
当类中操作的引用数据类型不确定时,我们可以自定义泛型类。
class Tools<T>
{
}
public class Test {
public static void main(String[] args) {
new Tools<String>().sop("test.");
}
}
class Tools<T> {
public void sop(T t) {
System.out.println(t);
}
}
看上面的程序,在定义Tools类时,不知道要操作的是什么类型,因此将Tools定义为泛型类,到使用时确定操作对象为String类型,就将类型参数指定为String了。
#泛型方法
泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。
public <T> void show(T t)
// 注意:<>放在修饰符后面,返回值前面
{
}
public class Test {
public static void main(String[] args) {
Tool_A<String> a = new Tool_A<String>();
a.sop("a");
a.sop(1); //编译时报错
a.show(1.2222);
Tool_B b = new Tool_B();
b.show("a");
b.show(1);
}
}
class Tool_A<T> {
// 该类A是泛型类,这个sop方法根据类型参数,确定运行时操作的类型
public void sop(T t) {
System.out.println("Tool_A sop: " + t);
}
// 泛型类和泛型方法可以同时定义,且不冲突。这个show方法是泛型方法,,可以接收不同的类型
public <T> void show(T t) {
System.out.println("Tool_A show: " + t);
}
}
class Tool_B {
// 如果既不是泛型类,又不是泛型方法,方法参数的类型必须确定
public void show(String t) {
System.out.println("Tool_B show: " + t);
}
// 该类B不是泛型类,这个show方法是泛型方法,可以接收不同的类型
public <T> void show(T t) {
System.out.println("Tool_B show: " + t);
}
}
特殊情况:
class Tool_A<T> {
public static void method(T t) { //错,静态方法不可以访问定义类上的泛型
}
public static <T> void method(T t) {//对,如果静态方法操作的引用数据类型不确定,可将泛型定义在方法上
}
}
#泛型接口
class Aclass implements A<String>{
@Override
public void sop(String t) {
// TODO Auto-generated method stub
}
}
interface A<T>{
public abstract void sop(T t);
}
泛型还能定义在接口上,如果定义泛型接口后还是不知道什么类型,可以将实现类继续定义为泛型类,由实现类确定具体类型。
#泛型限定
- < ? >代表通配符,用于接收不确定的类型
- < ? extends E > : 可以接收E类型或者E的子类型。
- < ? super E >: 可以接收E类型或者E的父类型。
import java.util.*;
public class Test {
public static void main(String[] args) {
ArrayList<String> al1 = new ArrayList<String>();
al1.add("AL1");
al1.add("AL2");
al1.add("AL3");
ArrayList<Integer> al2 = new ArrayList<Integer>();
al2.add(1);
al2.add(2);
al2.add(3);
printCollection(al1);
printCollection(al2);
}
public static void printCollection(ArrayList<?> al) {
Iterator<?> it = al.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
这个程序,如果printCollection(ArrayList< ? > al)改为printCollection(ArrayList< T > al)会出错,因为上面**< T >这种形式是在声明泛型的类或方法的时候限制了可以用的泛型类型;而< ? >形式是在使用的时候限制**了引用的类型。
//对上面的程序来说,以下情况两句printCollection都错
printCollection(ArrayList<T> al) { ×
//对上面的程序来说,以下情况printCollection(al1);错
printCollection(ArrayList<Integer> al) { ×
import java.util.*;
public class Test {
public static void main(String[] args) {
//TreeSet(Comparator<? super E> comparator)
TreeSet<Student> ts = new TreeSet<Student>(new PersonComparator());
ts.add(new Student(12));
ts.add(new Student(14));
ts.add(new Student(13));
System.out.println(ts);//[12, 13, 14]
}
}
class Person {
public int age;
}
class Student extends Person {
public Student(int age) {
this.age = age;
}
@Override
public String toString() {
return Integer.toString(this.age);
}
}
class PersonComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return new Integer(p1.age).compareTo(new Integer(p2.age));
}
}
上面的程序,由于TreeSet指定的比较器使用了泛型限定TreeSet(Comparator< ? super E > comparator) ,因此就算再写一个Person的子类Worker,也可以直接继续用这个比较器,很方便。