由来
早期的时候,Java使用Object来代表任意的类型。向上转型是没有任何问题的,但是在向下转型的时候其实隐含了类型转换的问题。这样的程序其实并不是安全的。
public class ObjectTool {
private Object obj;
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
}
public class ObjectToolDemo {
public static void main(String[] args) {
ObjectTool ot = new ObjectTool();
// 正常使用
ot.setObj(new Integer(27));
Integer i = (Integer) ot.getObj();
System.out.println("年龄是:" + i);
ot.setObj(new String("jack"));
String s = (String) ot.getObj();
System.out.println("姓名是:" + s);
System.out.println("---------");
ot.setObj(new Integer(30));
// ClassCastException
String ss = (String) ot.getObj();
System.out.println("姓名是:" + ss);
}
}
代码 29 行,报错"java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String",因为写入的是 Integer 类型,而读取用 String 类型向下转型,所以在运行期间报错。
能不能在写入的时候动态明确类型,读取的时候不需要强制转换直接使用呢?
Java引入了泛型
。
Java 在 JDK5 后引入了泛型,泛型其实指的就是参数化类型
,使得代码可以适应多种类型。比如 Java 容器中(public class ArrayList<E> extends AbstractList<E>),就大量使用泛型,用来指定容器要持有什么类型的对象。而且,可以在编译期明确参数类型,防止运行期转换异常的问题。
//泛型类:把泛型定义在类上
public class ObjectTool<T> {
private T obj;
public T getObj() {
return obj;
}
public void setObj(T obj) {
this.obj = obj;
}
}
public class ObjectToolDemo {
public static void main(String[] args) {
ObjectTool<String> ot = new ObjectTool<String>();
// ot.setObj(new Integer(27)); //这个时候编译期间就过不去
ot.setObj(new String("jack"));
System.out.println("姓名是:" + ot.getObj());
ObjectTool<Integer> ot2 = new ObjectTool<Integer>();
// ot2.setObj(new String("jack"));//这个时候编译期间就过不去
ot2.setObj(new Integer(27));
System.out.println("年龄是:" + ot2.getObj());
}
}
使用泛型类,可以在创建 ObjectTool<String> ot = new ObjectTool<String>();
明确类型String。插入其他类型数据 ot.setObj(new Integer(27));
编译期间就会报错。读取数据 ot.getObj()
,也不需要强制转换(向下转型)。
概述
泛型是一种把明确类型的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。
格式:<数据类型> 此处的数据类型只能是引用类型。
因为集合可以存储多种数据类型的引用,而用的时候需要进行强制转换。如果只进行单一强制类型转换,就会出错。而泛型可以在编译期间指定类型,就避免运行时报错。而且,可以避免强制转换 。
- 优点
- 编译期间指定类型,保证了类型安全
- 消除了强制类型转换
- 提高了代码的通用性
- 提高了性能(其实没有…,因为编译泛型时会自动加入类型转换的编码。但是,运行期间的性能确实提高了:) )
public class GenericDemo {
public static void main(String[] args) {
// 创建
ArrayList<String> array = new ArrayList<String>();
// 添加元素
array.add("hello");
array.add("world");
array.add("java");
// 遍历
Iterator<String> it = array.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
}
}
输出:
hello
world
java
Iterator<String> it = array.iterator();
指定类型后,it.next();
就不需要强制转换。
分类
泛型类
public class Generic<A, B, C> {
private A a;
private B b;
private C c;
public Generic(A a, B b, C c){
this.a = a;
this.b = b;
this.c = c;
}
public String toString(){
return "(" + a + "." + b + "." + c + ")";
}
}
Class<T>
也是泛型类。T 代表一个类型 ,而 Class<T> 代表这个类型所对应的类, Class<?> 表示类型不确定的类。
public class ObjectTool<T> {
public Class<T> test (Class<T> t){
System.out.println(t);
return t;
}
}
public class ObjectToolDemo {
public static void main(String[] args) {
ObjectTool<String> ot = new ObjectTool<String>();
//Class<Integer> test = ot.test(String.class); 编译报错
Class<String> test = ot.test(String.class);
System.out.println(test);
}
}
输出:
class java.lang.String
class java.lang.String
泛型接口
把泛型定义在接口上
public interface Inter<T> {
public abstract void show(T t);
}
1、实现类知道该是什么类型的。
public class InterImpl implements Inter<String> {
@Override
public void show(String t) {
System.out.println(t);
}
}
2、实现类如果还不知道是什么类型的,可以沿用接口泛型。
public class InterImpl<T> implements Inter<T> {
@Override
public void show(T t) {
System.out.println(t);
}
}
泛型方法
泛型方法有一个基本原则,尽量使用泛型方法而不是泛型类。只要能够用泛型方法达到需求,就应该只用泛型方法,这样能使得代码更加清晰。
格式:泛型参数列表置于返回值前,例如
public <T> void f(T t)
,返回值也可以使用泛型,public <T> T f(T t)
。
public class ObjectTool {
private Object obj;
public <T> T getObj() {
return (T)obj;
}
public <T> void setObj(T t) {
this.obj = t;
System.out.println(t);
}
}
public class ObjectToolDemo {
public static void main(String[] args) {
ObjectTool ot = new ObjectTool();
ot.setObj(new String("lili"));
String s = ot.getObj();
System.out.println("姓名是:" + ot.getObj());
System.out.println("---------");
ot.setObj(100);
Integer ss = ot.getObj();
System.out.println("年龄是:" + ss);
}
}
输出:
lili
姓名是:lili
---------
100
年龄是:100
小结
本篇介绍了泛型的由来、概述,说明了泛型带来的好处。介绍了泛型类、泛型接口、泛型方法的用法。但是,泛型也消除了类型,下篇将介绍泛型的缺点以及解决方案。