- 泛型的解释
现在感觉泛型是一个值得学习的地方,就抽出时间来学习和总结一下泛型的使用。
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
泛型是一种把类型的明确工作推迟到创建对象或者调用方法的时候才去明确的特殊类型。
注意:类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。
- 泛型出现的原因
早期的时候,使用Object来代表任意类型。但是这样在向上转型的是没有问题的,但是在向下转型的时候存在类型转换的问题,这样的程序其实是不安全的。所以Java在JDK5之后提供了泛型来解决这个问题。
使用泛型的典型例子,是在集合中的泛型使用。
在使用泛型前,存入集合中的元素可以是任何类型的,当从集合中取出时,所有的元素都是Object类型,需要进行向下的强制类型转换,转换到特定的类型。
泛型的思想就是由程序员指定类型,这样集合就只能容纳该类型的元素。
- 实例分析
在JDK1.5之前,Java泛型程序设计是用继承来实现的。因为Object类是所用类的基类,所以只需要维持一个Object类型的引用即可。就比如ArrayList只维护一个Object引用的数组:
public class ArrayList//JDK1.5之前的 { public Object get(int i){......} public void add(Object o){......} ...... private Object[] elementData; }
- 这样会有两个问题:
1、没有错误检查,可以向数组列表中添加类的对象
2、在取元素的时候,需要进行强制类型转换。这样,很容易发生错误,比如:
/**jdk1.5之前的写法,容易出问题*/ ArrayList arrayList1=new ArrayList(); arrayList1.add(1); arrayList1.add(1L); arrayList1.add("asa"); int i=(Integer) arrayList1.get(1);//因为不知道取出来的值的类型,类型转换的时候容易出错
- 这里的第一个元素是一个长整型,而你以为是整形,所以在强转的时候发生了错误。
所以。在JDK1.5之后,加入了泛型来解决类似的问题。例如在ArrayList中使用泛型:
/** jdk1.5之后加入泛型*/ ArrayList<String> arrayList2=new ArrayList<String>(); //限定数组列表中的类型 // arrayList2.add(1); //因为限定了类型,所以不能添加整形 // arrayList2.add(1L);//因为限定了类型,所以不能添加整长形 arrayList2.add("asa");//只能添加字符串 String str=arrayList2.get(0);//因为知道取出来的值的类型,所以不需要进行强制类型转换
还要明白的是,泛型特性是向前兼容的。尽管 JDK 5.0 的标准类库中的许多类,比如集合框架,都已经泛型化了,但是使用集合类(比如 HashMap 和 ArrayList)的现有代码可以继续不加修改地在 JDK 1.5 中工作。当然,没有利用泛型的现有代码将不会赢得泛型的类型安全的好处。
一、泛型类(注意:一旦在类上声明泛型,在类里面所有非静态成员上都可以使用)
格式:public class 类名<参数类型,...>{} 当然这里<>里面也可以使用多个不同参数类型例如:public class User<T,E>{}
注意:类型变量使用大写形式,且比较短,这是很常见的。在Java库中,使用变量E表示集合的元素类型,K和V分别表示关键字与值的类型。(需要时还可以用临近的字母U和S)表示“任意类型”。
public class ObjectTool<T> { private T obj; public void setObj(T obj) { this.obj = obj; } public T getObj() { return obj; } } public static void main(String[] args) { ObjectTool<String> obj = new ObjectTool<>(); obj.setObj("Hello World."); System.out.println(obj.getObj()); }
二、泛型方法
格式:public <T> 返回值 方法名(T a){}
public class ObjectTool { public <E> void show(E s) { System.out.println(s); } }
public <E> void show(E s) { System.out.println(s); } public static void main(String[] args) { ObjectTool obj = new ObjectTool(); obj.show("Hello world.");
obj.show(120); }
- 方法上的泛型和类上的泛型很像,唯一不同的是类型的作用域不同
三、泛型通配符
<?>:类型通配符一般是使用?代替具体的类型参数。例如 List<?> 在逻辑上是List<String>,List<Integer> 等所有List<具体类型实参>的父类。
//泛型如果明确的写的时候,前后类型必须一致 Collection<Object> c1 = new ArrayList<Object>(); Collection<Object> c2 = new ArrayList<Animal>(); //报错 Collection<Object> c3 = new ArrayList<Dog>(); //报错 //?表示任意类型都是可以的 Collection<?> c4 = new ArrayList<Object>(); Collection<?> c5 = new ArrayList<Animal>(); Collection<?> c6 = new ArrayList<Dog>();
<? extends E>:向下限定,只能是E及其子类
Collection<? extends Animal> c1 = new ArrayList<Object>(); //报错 Collection<? extends Animal> c2 = new ArrayList<Animal>(); Collection<? extends Animal> c3 = new ArrayList<Dog>(); Collection<? extends Animal> c4 = new ArrayList<Cat>();
<? super E>:向上限定,只能是E及其父类
Collection<? super Animal> c1 = new ArrayList<Object>(); Collection<? super Animal> c2 = new ArrayList<Animal>(); Collection<? super Animal> c3 = new ArrayList<Dog>(); //报错 Collection<? super Animal> c4 = new ArrayList<Cat>(); //报错
四、继承泛型类别
父类:
public class Parent<T1,T2> { private T1 foo1; private T2 foo2; public T1 getFoo1() { return foo1; } public void setFoo1(T1 foo1) { this.foo1 = foo1; } public T2 getFoo2() { return foo2; } public void setFoo2(T2 foo2) { this.foo2 = foo2; } }
子类:
public class Child<T1, T2, T3> extends Parent<T1, T2> { private T3 foo3; public T3 getFoo3() { return foo3; } public void setFoo3(T3 foo3) { this.foo3 = foo3; } }
五、实现泛型接口
泛型接口
public interface ParentInterface<T1,T2> { public void setFoo1(T1 foo1); public void setFoo2(T2 foo2); public T1 getFoo1(); public T2 getFoo2(); }
子类实现泛型接口:
public class ChildClass<T1,T2> implements ParentInterface<T1, T2> { private T1 foo1; private T2 foo2; @Override public void setFoo1(T1 foo1) { this.foo1 = foo1; } @Override public void setFoo2(T2 foo2) { this.foo2 = foo2; } @Override public T1 getFoo1() { return this.foo1; } @Override public T2 getFoo2() { return this.foo2; } }
还可以在实现接口的时候定义类型:
interface Show<T,U>{ void show(T t,U u); } class ShowTest implements Show<String,Date>{ @Override public void show(String str,Date date) { System.out.println(str); System.out.println(date); } }
测试一下:
public static void main(String[] args) throws ClassNotFoundException { ShowTest showTest=new ShowTest(); showTest.show("Hello",new Date()); }
-
不允许使用泛型的地方
public class GenericsExample<T> { private static T member; //This is not allowed }
public class GenericsExample<T> { public GenericsExample(){ new T(); } }
final List<int> ids = new ArrayList<>(); //不允许 final List<Integer> ids = new ArrayList<>(); //允许
// 引起编译错误 public class GenericException<T> extends Exception {}