集合可以存储任何类型的对象,但是当把一个对象存入集合后,集合会忘记这个对象的类型,将该对象从集合中取出时,这个对象的编译类型就变成了 Object 类型。换句话说,在程序中无法确定一个集合中的元素到底是什么类型的,那么在取出元素时,如果进行强制类型转换就很容易出错。
通过案例演示这种情况:
import java.util.ArrayList;
public class Example{
public static void main(String[] args){
ArrayList list = new ArrayList(); //创建 ArrayList 集合
list.add("String"); //添加字符串对象
list.add("Collection");
list.add(1); //添加 Integer 对象
for(Object obj: list){ //遍历集合
String str = (String) obj; //强制转换成 String 类型
}
}
}
此代码遍历元素并取出元素时,都将它们强制转换为 String 类型,由于 Integer 对象无法转换为 String 类型,因此会报错。
为了解决这个问题,在 Java 中引入了 “参数化类型” 这个概念,即泛型。它可以限定方法操作的数据类型,在定义集合类时,使用 “<参数化类型>” 的方式指定该类中方法操作的数据类型,具体格式如下:
ArrayList<参数化类型> list = new ArrayList <参数化类型> ();
Example.java 示例代码:
import java.util.ArrayList;
public class Example{
public static void main(String[] args){
//创建 ArrayList 集合对象,并指定泛型为 String
ArrayList<String>list = new ArrayList<String>();
list.add("String"); //添加字符串对象
list.add("Collection");
for(String str: list){
System.out.println(str); //强制转换成 String 类型
}
}
}
**注意:**在使用泛型后每次遍历集合元素时,可以指定元素类型为 String,而不是 Object,这样就避免了在程序中进行强制类型转换
自定义泛型
假设要实现一个简单的容器,用于缓存程序中的某个值,此时要定义两个方法 save() 和 get(),一个用于保存数据,另一个用于取出数据。
为了能存储任意类型的对象,save()方法的参数需要定义为 Object 类型,同样 get() 方法的返回值也需要是 Object 类型。但当使用 get() 方法取出这个值时,有可能忘记当初存储的是什么类型的值,在取出时将其转换为 String 类型,这样程序就会发生错误。
Example.java 示例代码:
class CachePool{
Object temp;
public void save(Object temp){
this.temp = temp;
}
public Object get(){
return temp;
}
}
public class Example{
public static void main(String[] args){
CachePool pool = new CachePool(); //创建 CachePool 对象
pool.save(new Integer(1)); //存入数据
String temp = pool.get(); //取出数据
System.out.println(temp);
}
}
从运行结果可以看出,存入了一个 Integer 类型的数据,在取出这个数据时,将该数据转换成了 String 类型,出现了类型不匹配的错误。
为了避免这个问题,可以使用泛型。在定义一个类 CachePool 时,使用<
T>
声明参数类型,将 save() 方法的参数类型和 get() 方法的返回值类型都声明为 T,那么在存入元素时,元素的类型被限定了,容器中就只能存入这种 T 类型的元素,在取出元素时就无须进行类型转换。
Example.java 示例代码:
class CachePool<T>{ //在创建类时,声明参数类型为 T
T temp;
public void save(T temp){ //在创建 save() 方法时,指定参数类型为 T
this.temp = temp;
}
public T get(){ //在创建 get() 方法时,指定返回值类型为 T
return temp;
}
}
public class Example{
public static void main(String[] args){
//在实例化对象时,传入参数为 Integer 类型
CachePool<Integer>pool = new CachePool<Integer>();
pool.save(new Integer(1));
Integer temp = pool.get();
System.out.println(temp);
}
}
此代码,在定义 CachePool 类时,声明了参数类型为 T,在实例化对象时通过<
Integer>
将参数 T 指定为 Integer 类型,同时在调用 save() 方法时传入的数据也是 Integer 类型,那么调用 get() 方法取出的数据自然就是 Integer 类型,这样做的好处是不需要进行类型转换。