泛型
概念
在《Java编程思想》当中是这样说的:一般的类和方法,只能使用具体的类型: 要么是基本类型,要么是自定义的类。如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。也就是说,泛型是适用于多种类型的。把泛型作为了参数进行传递。
实例
泛型是将数据类型参数化,进行传递。可以将数据类型参数化,编译时自动进行类型检查和转换。
通过 Object 放入多种数据类型
在之前创建对象的时候,创建的 class 类只能放一种数据,如果使用泛型的话,就能放多种数据。也就是把类写成 Object 类型。代码如下:
classMyArray1{publicObject[] objects =newObject[10];publicvoidset(int pos,Object val){
objects[pos]= val;}publicObjectget(int pos){return objects[pos];}}publicstaticvoidmain(String[] args){MyArray1 myArray =newMyArray1();
myArray.set(0,"hello");
myArray.set(1,10);//什么都能存进去,但是取出的时候要强制转换String str =(String) myArray.get(0);}
如上面的代码,在放入数据的时候,什么都能放。但是取出的时候,就需要强制转换才可以,因为 get 拿到的是 Object 类型,所以要强制转换。
泛型写法
通过在 class 类后面加一个参数,来实现每次对数据的指定。代码如下:
classMyArray<T>{publicT[] objects =(T[])newObject[10];publicvoidset(int pos,T val){
objects[pos]= val;}publicTget(int pos){return objects[pos];}publicT[]getArray(){return objects;}}publicstaticvoidmain(String[] args){MyArray<String> myArray =newMyArray();
myArray.set(0,"hello");String str = myArray.get(0);}
类名后的 <T> 代表占位符,来表示当前是一个泛型类,这里指定类型是 String ,也就是只能存放 String 类型的数据。但是简单类型(基本类型)不能做泛型的参数。输出的时候就不需要强制转换了,编译器会自动完成。如果放非 String 类型的话,就会报错:
通过观察编译的过程,可以发现所有的 <T> 都变成了 Object 数组,通过字节码文件查看。如下图:
也就是说,在编译过程当中,将所有的 T 替换为 Object 这种机制,就是:擦除机制。
泛型的上界
泛型可以继承,泛型所继承的就是泛型的上界。extends 又叫拓展。如果没有指定的话,泛型的上界就是 Object 。
classMyArray2<TextendsNumber>{publicT[] objects =(T[])newObject[10];publicvoidset(int pos,T val){
objects[pos]= val;}publicTget(int pos){return objects[pos];}publicT[]getArray(){return objects;}}publicstaticvoidmain(String[] args){MyArray2<Integer> array1 =newMyArray2<>();MyArray2<Number> array2 =newMyArray2<>();//MyArray2<String> array3 = new MyArray2<>();//报错
array1.set(0,10);//array1.set(1,12.5);//报错
array2.set(0,10);
array2.set(1,12.5);}
这里 MyArray2 的上界就是 Number 所以,数组类型只能写 Number 类的,写 String 就会报错:
因为 array1 是 Integer 类型,所以存放小数的时候也会报错:
写泛型类,求出数组当中的最大值
在求数组最大值的时候,因为是泛型类,所以在传递的时候都是传的引用类型,所以要实现 Comparable 接口才可以进行比较大小。这里通过 Comparable 接口来实现上界进行比较。代码如下:
classAlg<TextendsComparable<T>>{publicTfindMax(T[] array){T max = array[0];for(int i =0; i < array.length; i++){if(max.compareTo(array[i])<0){
max = array[i];}}return max;}}publicstaticvoidmain(String[] args){Alg<Integer> alg1 =newAlg<>();Integer[] array ={1,2,3,4};System.out.println(alg1.findMax(array));}
运行结果如下:
静态泛型方法
实现泛型的静态方法,通过静态方法来直接找到最大值。:
classAlg2{publicstatic<TextendsComparable>TfindMax(T[] array){T max = array[0];for(int i =0; i < array.length; i++){if(max.compareTo(array[i])<0){
max = array[i];}}return max;}}publicstaticvoidmain9(String[] args){Integer[] array ={1,2,3,4};System.out.println(Alg2.<Integer>findMax(array));}
这里要注意的是,因为比较的时候,不是简单类型,是 Integer 类型,所以在定义数组的时候,不能用 int 这样的简单类型。因为是 static 修饰的,所以这里可以直接调用方法。运行结果如下:
泛型当中的父子类关系
理论上来说 Object 是所有类的父类,这些东西在编译完成的时候,都被擦除掉了,所以在 JVM 当中,也就不存在父子类关系了。
通配符
通配符 ? 用在泛型当中,是为了解决泛型无法完成协变的问题的。协变:指的就是如果 Student 是 Person 的子类,那么 List<Student> 也应该是 List<Person> 的子类。但是泛型是不支持这样的父子类关系的。如下示例,输出 list 当中的数据:
代码一:
publicstatic<T>voidprintList1(ArrayList<T> list){for(T x:list){System.out.println(x);}}
此时代码的参数是 T ,此时的 T 是指定的一个泛型参数。
代码二:
publicstaticvoidprintList2(ArrayList<?> list){for(Object x:list){System.out.println(x);}}
代码二当中,使用了通配符 ? ,此时传入 printList2 的,具体是什么数据类型,是不知道的。就像如下代码,通过通配符来输出 list :
classAlg3{publicstaticvoidprint2(ArrayList<?> list){for(Object x:list){System.out.println(x);}}}publicstaticvoidmain(String[] args){ArrayList<Integer> list =newArrayList<>();
list.add(1);
list.add(2);Alg3.print2(list);}
这里就是,不管传的是什么类型,输出那里都能匹配上。输出结果如下:
通配符的上界
通过通配符来获取到上界,也就是可以引用自己的子类。如下代码:
class up {ArrayList<Integer> arrayList1 =newArrayList<>();ArrayList<Double> arrayList2 =newArrayList<>();List<?extendsNumber> list = arrayList1;Number a = list.get(0);}
因为 Number 是 Integer 和 Double 的父类,所以这里可以直接引用 arrayList1 .但是通配符的上界不适合写入。适合读取。 因为此时的 list 可以引用的子类对象很多,编译器无法确定具体的类型。编译器为了安全起见,只允许进行读取。
通配符的下界
使用 super 就是可以引用 “父类” 。
- MyArrayList<? super Integer> 是 MyArrayList的父类类型
- MyArrayList<?> 是 MyArrayList<? super Integer>的父类类型
下界是不允许读取的。允许写入。如果要一定要去读取的话,通过 Object 来读取。,代码示例:
classPerson{}classStudentextendsPerson{}classCextendsStudent{}publicstaticvoidmain(String[] args){ArrayList<?superPerson> arrayList1 =newArrayList<Person>();
arrayList1.add(newPerson());
arrayList1.add(newStudent());
arrayList1.add(newC());ArrayList<?superPerson> arrayList2 =newArrayList<>();
arrayList2.add(newPerson());
arrayList2.add(newStudent());Object o = arrayList1.get(0);System.out.println(o);}
运行结果如下:
通过 Object 方法,就拿到了实例。
版权归原作者 Lockey-s 所有, 如有侵权,请联系我们删除。