没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
实例一:泛型初识
①定义一个Student类
public class Student {
private String name;
private 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;
}
}
②定义Test类
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Student student1 = new Student();
student1.setName("leelit");
Student student2 = new Student();
student2.setName("lina");
List<Object> list1 = new ArrayList<>();
list1.add(student1);
list1.add(student2);
System.out.println(((Student) list1.get(0)).getName());
System.out.println(list1.get(1)); // must cast to (Student)
List<Student> list2 = new ArrayList<>();
list2.add(student1);
list2.add(student2);
System.out.println(list2.get(0).getName());
System.out.println(list2.get(1).getName());
}
}
打印结果:
leelit
Student@1db9742
leelit
lina
由Test类注释的地方还有打印结果可以知道泛型的作用是编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,如果用Object类来实现则需要显式类型转换。
实例二:自定义泛型
①定义一个Student类
public class Student {
private String name;
private 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 class Generic<T> {
T obj;
public T getObj() {
return obj;
}
public void setObj(T obj) {
this.obj = obj;
}
}
③定义第二个泛型
public class Generic2<T, P> {
private T obj1;
private P obj2;
public T getObj1() {
return obj1;
}
public void setObj1(T obj1) {
this.obj1 = obj1;
}
public P getObj2() {
return obj2;
}
public void setObj2(P obj2) {
this.obj2 = obj2;
}
}
④Test类
public class Test {
public static void main(String[] args) {
// TODO 自动生成的方法存根
// 泛型参数设为String类
Generic<String> generic = new Generic<>();
generic.setObj("hello");
System.out.println(generic.getObj());
// 泛型参数设为Student类
Student student = new Student();
student.setName("leelit");
student.setAge(21);
Generic<Student> generic1 = new Generic<>();
generic1.setObj(student);
System.out.println(generic1.getObj().getName() + " "
+ generic1.getObj().getAge());
// 泛型有两个参数
Generic2<Student, Double> generic2 = new Generic2<>();
generic2.setObj1(student);
generic2.setObj2(new Double(99.9));
System.out.println(generic2.getObj1().getName() + " "
+ generic2.getObj1().getName() + " " + generic2.getObj2());
}
}
打印结果:
hello
leelit 21
leelit leelit 99.9
这个实例说明:
1、泛型的类型参数只能是类,不能是简单类型。
2、泛型的类型参数可以有多个。
实例三:有界类型、通配符类型、泛型方法。(文章文字部分主要引自百度百科,以下例子也是)
①定义一个有界类型的泛型
import java.util.Collection;
public class CollectionGenFoo<T extends Collection> { //这样类中的泛型T只能是Collection接口的实现类,如果不是接口则是本类或继承类
private T x;
public CollectionGenFoo(T x) {
this.x = x;
}
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
}
②Test类
import java.util.ArrayList;
import java.util.Collection;
public class Test {
public static void main(String args[]) {
CollectionGenFoo<ArrayList> listFoo = null;
listFoo = new CollectionGenFoo<ArrayList>(new ArrayList());
// 出错了,不让这么干。
// CollectionGenFoo<Collection> listFoo1 = null;
// listFoo1=new CollectionGenFoo<ArrayList>(new ArrayList());
System.out.println("实例化成功!");
Test test = new Test();
test.f(test);
test.f("");
test.f("", 5);
}
public <T> void f(T x) { //泛型方法
System.out.println(x.getClass().getName());
}
public <T,P> void f(T x, P y) { //泛型方法为两个参数
System.out.println(x.getClass().getName() + " "
+ y.getClass().getName());
}
}
打印结果:
实例化成功!
Test
java.lang.String
java.lang.String java.lang.Integer
是否拥有泛型方法,与其所在的类是否泛型没有关系。要定义泛型方法,只需将泛型参数列表置于返回值前
③重新定义一个Test类测试通配符
为了解决类型被限制死了不能动态根据实例来确定的缺点,引入了“通配符泛型”,针对上面的例子,使用通配泛型格式为<? extends Collection>,“?”代表未知类型,这个类型是实现Collection接口。public class Test {
public static void main(String args[]) {
CollectionGenFoo<ArrayList> listFoo = null;
listFoo = new CollectionGenFoo<ArrayList>(new ArrayList());
// 现在不会出错了
CollectionGenFoo<? extends Collection> listFoo1 = null;
listFoo1 = new CollectionGenFoo<ArrayList>(new ArrayList());
System.out.println("实例化成功!");
}
}
2、通配符泛型不单可以向下限制,如<? extends Collection>,还可以向上限制,如<? super Double>,表示类型只能接受Double及其上层父类类型,如Number、Object类型的实例。
小结:泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。