Java泛型小结
1 为什么要有泛型
(1). 解决元素存储的安全性问题
(2). 解决获取数据元素时,需要类型强转的问题
泛型,JDK1.5新加入的,解决数据类型的安全性问题,其主要原理是在类声明时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这样在类声明或实例化时只要指定好需要的具体的类型即可。Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮。
体会:使用泛型的主要优点是能够在编译时而不是在运行时检测错误。
2 使用泛型
(1).泛型的声明
interface List<T> 和 class GenTest<K,V> 其中,T,K,V不代表值,而是表示类型。这里使用任意字母都可以。常用T表示,是Type的缩写。
(2).泛型的实例化:一定要在类名后面指定类型参数的值(类型)。如:
List<String> strList = new ArrayList<String>();
Iterator<Customer> iterator = customers.iterator();
T只能是类,不能用基本数据类型填充。但可以使用包装类填充 把一个集合中的内容限制为一个特定的数据类型,这就是generics背后的核心思想。
3 泛型的几个重要应用
3.1在集合中使用泛型
1. 对象实例化时不指定泛型的话,默认为:Object。
2. 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如<E1,E2,E3>
3. 泛型类的构造器如下: public GenericClass(){}。而如下是错误的: public GenericClass<E>(){}
4.从泛型类派生子类,泛型类型需具体化
5.如果泛型类是一个接口或抽象类,则不可创建泛型类的对象。
6.静态方法中不能使用类的泛型
7.异常类不能是泛型的
8.加入集合中的对象类型必须与指定的泛型类型一致。
9.泛型不同的引用不能相互赋值。尽管在编译时ArrayList<String>和ArrayList<Integer>是两种类型,但是,在运行时只有一个ArrayList被加载到JVM中。
10. 泛型的指定中不能使用基本数据类型,可以使用包装类替换。
11. 不能使用new E[]。但是可以: E[] elements = (E[])new Object[capacity];
3.2自定义泛型类
class Person<T>{
//使用T类型定义变量
private T info;
//使用T类型定义一般方法
public T getInfo(){
return info;
}
public void setInfo(T info){
this.info = info;
}
//使用T类型定义构造器
public Person(){}
public Person(T info){
this.info = info;
}
//static的方法中不能声明泛型
//public static void show(T t){
//}
//不能在try-catch中使用泛型定义
//try{}
//catch(MyException<T> ex){}
}
3.3自定义泛型方法
方法,也可以被泛型化,不管此时定义在其中的类是不是泛型类。在泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型。 泛型方法的格式: [访问权限] <泛型> 返回类型 方法名([泛型标识 参数名称]) 抛出的异常。
public class DAO {
public <E> E get(int id, E e){
E result = null;
return result;
}
}
4 泛型在继承上的体现
如果B是A的一个子类型(子类或者子接口),而G是具有泛型声明的类或接口,G<B>并不是G<A>的子类型! 比如:String是Object的子类,但是List<String >并不是List<Object>的子类。
public void testGenericAndSubClass() {
Person[] persons = null;
Man[] mans = null;
// 而 Person[] 是 Man[] 的父类.
persons = mans;
Person p = mans[0];
// 在泛型的集合上
List<Person> personList = null;
List<Man> manList = null;
// personList = manList;(报错)
}
5 通配符的使用
1.使用类型通配符:? 比如:List<?> ,Map<?,?> List<?>是List<String>、List<Object>等各种泛型List的父类。
2.读取List<?>的对象list中的元素时,永远是安全的,因为不管list的真实类型是什么,它包含的都是Object。
3.写入list中的元素时,不行。因为我们不知道c的元素类型,我们不能向其中添加对象。 唯一的例外是null,它是所有类型的成员。
将任意元素加入到其中不是类型安全的: Collection<?> c = new ArrayList<String>(); c.add(new Object()); // 编译时错误 因为我们不知道c的元素类型,我们不能向其中添加对象。
add方法有类型参数E作为集合的元素类型。我们传给add的任何参数都必须是一个未知类型的子类。因为我们不知道那是什么类型,所以我们无法传任何东西进去。 唯一的例外的是null,它是所有类型的成员。
另一方面,我们可以调用get()方法并使用其返回值。返回值是一个未知的类型,但是我们知道,它总是一个Object。
public static void main(String[] args) {
List<?> list = null;
list = new ArrayList<String>();
list = new ArrayList<Double>();
//list.add(3);
list.add(null);
List<String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
l1.add(“一枝韩独秀");
l2.add(15);
read(l1);
read(l2); }
static void read(List<?> list){
for(Object o : list){
System.out.println(o);
}
}
<?> 允许所有泛型的引用调用
举例: <? extends Number> (无穷小 , Number] 只允许泛型为Number及Number子类的引用调用
<? super Number> [Number , 无穷大) 只允许泛型为Number及Number父类的引用调用
<? extends Comparable> 只允许泛型为实现Comparable接口的实现类的引用调用
public static void printCollection3(Collection<? extends Person> coll){
//Iterator只能用Iterator<?>或Iterator<? extends Person>.why?
Iterator<?> iterator = coll.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
} }
public static void printCollection4(Collection<? super Person> coll){
Iterator<?> iterator = coll.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}