在JDK1.5版本中提供了泛型概念,泛型实质上就是使程序员定义安全的类型,在没有提供泛型之前,Java也提供了对Object的引用“任意化”操作,这种任意化操作就是对Object引用进行“向下转型”及“向上转型”操作,但某些强制类型转换的错误也许不会被编译器捕捉,所有强制类型转换存在完全隐患,于是提供了泛型机制。
一、回顾“向上转型”与“向下转型”
通过以下示例来回顾:
public class Test {
private Object b;
public Object getB() {
return b;
}
public void setB(Object b) {
this.b = b;
}
public static void main(String args[]) {
Test t =new Test();
t.setB(new Boolean(true));
System.out.println(t.getB());
t.setB(new Float(3.14));
Float f = (Float)(t.getB());
System.out.println(f);
}
}
/*输出结果如下:
true
3.14
*/
在上述示例中,Test类中定义了私有的成员变量b,它的类型为Object类型,同时为其第一轮相应的setXXX()与getXXX()方法。在类主方法中,将new Boolean(true)对象作为setB()方法的参数,由于setB()方法的参数类型使Object,这样就实现了“向上”转型。同时在调用getB()方法时,将getB()方法返回的object对象与相应的类型返回,这就是“向下转型”。
二、定义泛型
Object类为最上层的父类,很多程序员为了使程序更为通用。设计程序时通常使传入的值与返回值都以Object类型为主。当需要使用这些实例时,必须正确地将该实例转换为原来的类型,否则在运行时会发生ClassCastException异常。
泛型的语法如下:
类名<T>
//T代表一个类型的名称
通过以下示例来说明泛型的定义:
public class OverClass<T> {
private T over;
public T getOver() {
return over;
}
public void setOver(T over) {
this.over = over;
}
public static void main(String args[]) {
OverClass<Boolean> over1 = new OverClass<Boolean>();
OverClass<Float> over2 = new OverClass<Float>();
over1.setOver(true);
over2.setOver(3.14f);
Boolean b = over1.getOver();
Float f = over2.getOver();
System.out.println(b);
System.out.println(f);
}
}
/*输出结果如下:
true
3.14
*/
三、泛型的常规用法:
1、定义泛型类时声明多个类型
语法如下:
MutiOverClass<T1,T2>
//MutiOverClass:泛型类名称
其中,T1和T2为可能被定义的类型。
这样在实例化指定类型的对象时就可以指定多个类型,例如:
MutiOverClass<Boolean,Float> = new MutiOverClass<Boolean,Float>();
2、定义泛型类时声明数组类型
示例如下:
public class ArrayClass<T> {
public T[] array;
public void SetT(T[] array) {
this.array = array;
}
public T[] getT() {
return array;
}
public static void main(String args[]) {
ArrayClass<String> a = new ArrayClass<String>();
String[] array = {"成员1","成员2","成员3"};
a.SetT(array);
for(int i=0;i<a.getT().length;i++) {
System.out.println(a.getT()[i]);
}
}
}
/*输出结果如下:
成员1
成员2
成员3
*/
通过上述示例可见,可以在使用泛型机制时声明一个数组,但是不可以使用泛型来建立数组的实例,例如,下面的代码就是错误的:
public class ArrayClass<T>{
private T[] array = new T[10];
}
3、集合类声明容器的元素
可以使用K和V两个字符代表容器中的键值和与键值对应的具体值,示例如下:
public class TestClass<K,V> {
public Map<K, V>m = new HashMap<K, V>();
public void put(K k,V v) {
m.put(k, v);
}
public V get(K k) {
return m.get(k);
}
public static void main(String[] args) {
TestClass<Integer, String> tc = new TestClass<Integer, String>();
for(int i=0;i<5;i++) {
tc.put(i,"集合成员:"+i);
}
for(int i=0;i<tc.m.size();i++) {
System.out.println(tc.get(i));
}
}
}
/*输出结果如下:
集合成员:0
集合成员:1
集合成员:2
集合成员:3
集合成员:4
*/
在Java中有很多集合框架已经都被泛化了,可以在主方法中直接public Map<K,V> m = new HashMap<K,V>();语句创建实例,然后相应的调用Map接口中的put()与get()方法完成填充容器或根据键名获取集合中具体值的功能,下列几个时常用的被泛型化的集合类:
集合类 | 泛型定义 |
---|---|
ArrayList | ArrayLiset<E> |
HashMap | HashMap<K,V> |
HashSet | HashSet<E> |
Vector | Vector<E> |
示例如下:
public class AnyClass {
public static void main(String args[]) {
ArrayList<Integer> a = new ArrayList<Integer>();
a.add(1);
for(int i=0;i<a.size();i++) {
System.out.println("获取ArrayList容器的值:"+a.get(i));
}
Map<Integer, String> m = new HashMap<Integer, String>();
for(int i=0;i<5;i++) {
m.put(i,"成员:"+i);
}
for(int i=0;i<m.size();i++) {
System.out.println("获取Map容器的值:"+m.get(i));
}
Vector<String> v = new Vector<String>();
for(int i=0;i<5;i++) {
v.addElement("成员"+i);
}
for(int i=0;i<v.size();i++) {
System.out.println("获取Vector容器的值:"+v.get(i));
}
}
}
/*输出结果如下:
获取ArrayList容器的值:1
获取Map容器的值:成员:0
获取Map容器的值:成员:1
获取Map容器的值:成员:2
获取Map容器的值:成员:3
获取Map容器的值:成员:4
获取Vector容器的值:成员0
获取Vector容器的值:成员1
获取Vector容器的值:成员2
获取Vector容器的值:成员3
获取Vector容器的值:成员4
*/
四、泛化的高级用法:
1、限制泛型可用类型
默认可以使用任何类型来实例化一个泛型类对象,但Java中也对泛型类示例的类型错了限制,语法如下:
class 类名称<T extends anyClass>
//anyClass:某个接口或类
使用泛型限制后,泛型类的类型必须实现或继承了anyClass这个接口或类。无论anyClass是接口还是类,在进行泛型限制时都必须使用extends关键字,示例如下:
public class LimitClass<T extends List> {
public static void main(String[] args) {
LimitClass<ArrayList> l1 = new LimitClass<ArrayList>();
LimitClass<LinkedList> l2 = new LimitClass<LinkedList>();
//下面这句时错误的,因为HashMap没有实现List()接口
LimitClass<HashMap> l3 = new LimitClass<HashMap>();
}
}
2、使用类型通配符
在泛型机制中,提供了类型通配符,其主要作用是在创建一个泛型类对象时限制这个泛型类的类型实现或继承某个接口或类的子类,要声明这样一个对象可以使用"?"通配符来表示,同时使用extends关键字来对泛型加以限制,语法如下:
泛型类名称<? extends List>a = null;
3、继承泛型类与实现泛型接口
示例如下:
public class ExtendClass<T1> {
}
class SubClass<T1,T2,T3>extends ExtendClass<T1>{
}
如果在SubClass类继承ExtendClass类时保留父类的泛型类型,需要在继承时指明,如果没有指明,直接使用extends ExtendClass语句进行继承,则SubClass类张的T1、T2和T3都会自动变为Object,所有在一般情况下都将父类的泛型类型保留。
5、泛型总结
泛型的使用方法如下:
(1)泛型的类型参数只能时类类型,不可以时简单类型
(2)泛型的类型个数可以是多个
(3)可以使用extends关键字限制泛型的类型
(4)可以使用通配符限制泛型的类型