泛型的使用
一,泛型概述
关于泛型,先来说几句集合。都知道集合是可以存储任意对象,当我们创建一个集合时如果没有声明它的存储类型,那该集合便自动提升为Object类型。请参看如下代码:
public class GenericDemo { public static void main(String[] args) { Collection coll = new ArrayList(); coll.add("abc"); coll.add("hello"); coll.add(5);//由于集合没有做任何限定,任何类型都可以给其中存放 // 使用迭代器遍历集合 Iterator it = coll.iterator(); while(it.hasNext()){ //需要打印每个字符串的长度,就要把迭代出来的对象转成String类型 String str = (String) it.next(); System.out.println(str.length()); } } }
毫无疑问,以上代码会报错,首先从代码上看在集合中存储了数值类型,字符串类型。但是在使用迭代器遍历时,取出的是String类型的,那么对于数值类型来说就必然会报错。
那么以上问题该怎么解决呢?通常对于Collection集合来说,同一个集合对象只保存一种数据类型。如下代码所示:
// 存储字符类型 Collection<String> stringCollection = new ArrayList<>(); // 存储数值类型 Collection<Integer> integerCollection = new ArrayList<>(); // 存储精度类型 Collection<Double> doubleCollection = new ArrayList<>();
也就是说在我们初始化集合的时候,就已经将存储存储类型固定。但是按照Java的灵活性来说,这是显然不够的,比如预先并不确定要存储的类型。因此在JDK5之后新增了泛型的语法,使我们的程序显得更为灵活。
泛型:在方法或者类(接口)中预先的使用某种未知的数据类型。
**提示:**在我们创建对象的时候,如果没有明确指出一种数据类型,那么编译器会默认为Object类。
1.1,泛型的意义
那说了这么多,泛型又能解决什么问题呢?针对上面的案例分析:
1,可以将ClassCastException异常由运行期转到编译期异常。
2,避免强制类型的转换。
请看如上代码,在我们初始化集合时指定String数据类型,此时再存储数值类型就会在编译期报错,那么泛型又将如何运用呢。先别急,我们先看看集合中是如何定义的。
在Array List集合源码中看出,它的存储类型是一个E,这是什么呢?
- E,Elements:元素
- T,Type:类型
这就是泛型,因为我们对于集合来说它们并不知道我们要存储是什么类型,因此这就是泛型的意义。
**提示:**泛型是数据类型的一部分,我们将类名与泛型合并一起看做数据类型。
泛型,用来灵活地将数据类型应用到不同的类、方法、接口当中。将数据类型作为参数进行传递。
二,泛型类
编写格式:
修饰符 class 类名称<泛型变量>{}
我们还是以集合为例,请看如下集合源代码实现,以add方法作为参考。
可以看出add方法接收的数据类型为E,与我们上一节图片中所示Array List源码实现是一致的,因为Array List接收的参数类型就是E。说这么多有些啰嗦,现在先定义一个泛型类。
public class GenericClass<T> { private T key; public void setKey(T key){ this.key = key; } public T getKey(){ return key; } }
public class GenericDemo { public static void main(String[] args) { GenericClass<String> genericString =