我们先来看一段代码:
public static void main(String[] args) {
Collection collection = new ArrayList<>();
collection.add("hello");
collection.add("hello");
String[] objects = (String[]) collection.toArray();
System.out.println(Arrays.toString(objects));
}
执行结果如下:
对于这样的代码,我们在不了解泛型的理解是认为,在我们new出来collection之后,我们放的两个元素都是String类型的元素,因此我们就会想到取得时候利用强制类型转换,转换为String类型的数组去取,但是这段代码的底层原理远比我们想的要复杂的多,toArray()方法的返回值是一个Object【】数组,此处的强制类型实际上是将这个Object【】类型的数组强制类型转换为String【】数组,实际上,Object【】类型数组当中的每个元素并没有进行强制类型转换,因此,就会发生强制类型转换异常,只是运行时所抛出的异常,编译时期并不会察觉到。
我们再看一段代码,再来进行思考:
class MyArrayList{
private int[] elem;
private int usedSize;
public MyArrayList(){
this.elem = new int[10];
}
public void add(int val){
this.elem[usedSize] = val;
usedSize++;
}
public int get(int pos){
return this.elem[pos];
}
}
通过上面的代码我们思考:
(1)只能存放整数的类型,不通用
(2)能不能啥都可以放?String、Boolean....
我们对代码做出以下调整:
class MyArrayList{
private Object[] elem;
private int usedSize;
public MyArrayList(){
this.elem = new Object[10];
}
public void add(Object val){
this.elem[usedSize] = val;
usedSize++;
}
public Object get(int pos){
return this.elem[pos];
}
}
这样就又回到了最开始的问题,存放元素时,不能指定元素,什么都可以放,并且当我们取出数据的时候,都需要进行强制类型转换。
那么:
1、能不能我指定这个顺序表的类型?
2、指定类型之后,是不是就只能放指定类型的数据呢?
3、取出数据能不能不进行强制类型转换?
解决方案——泛型
泛型的意义:
1、自动对类型进行检查
2、自动对类型进行强制类型转换
泛型的核心操作:将类型作为参数进行传递。
我们先看代码如何实现:
class MyArrayList<E>{
private E[] elem;
private int usedSize;
public MyArrayList(){
this.elem = (E[]) new Object[10];
}
public void add(E val){
this.elem[usedSize] = val;
usedSize++;
}
public Object get(int pos){
return this.elem[pos];
}
}
我们指定传递的类型为String类型,注意,此处传递的类型只能是包装类型,不能是基本数据类型,当我们放置整数类型时,就会自动帮我们检查到错误并提示我们不能放置整数类型,换句话说,泛型是编译时期的一种机制(擦除机制)。
什么又是擦除机制呢?
所谓擦除机制,就是在编译时,将所有的E类型替换为Object类型。(具体细节我们在深入理解泛型时描述)。
我们可以参考标准库当中的做法来理解泛型:
获取时根据传递的参数对数据进行强制类型转换。