0


轻松掌握泛型

泛型

概念

在《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 方法,就拿到了实例。


本文转载自: https://blog.csdn.net/sjp151/article/details/123230586
版权归原作者 Lockey-s 所有, 如有侵权,请联系我们删除。

“轻松掌握泛型”的评论:

还没有评论