一、万能容器Object类型数组

Object类型作为所有类型的父类,如果我们将其定义成一个数组的类型,那么这个数组就可以存在各种类型的数据了,堪称“万能容器”,我们还可以写一个set,get方法以用来获取这个数值内的数据,假设我有MyArray这个类:
 

class MyArray{
    public Object[] objects = new Object[10];

    public void setObjects(int pos,Object a){
        this.objects[pos] = a;
    }
    public Object getObjects(int pos){
        return objects[pos];
    }

}

那我们发现,虽然这个数组可以存放各种类型的数据,但我们通过get方法得到的数据是父类Object这个类型的,所以我们在接收这个数据的时候需要用到强转

但想想,如果这个Object类型的数组特别大,里面存放了各种不同类型的数据,当你想取下标155号那个数据时,你能立马想到那个数据的类型是什么吗?如果去查,肯定要花上不少时间,那我们是否可以规定,这个引用指向的数组只能存int类型数据,那个引用指向的数组只能存String类型的数据呢?所以我们就要引出泛型这一概念了。

二、泛型

1.泛型的语法:

class 类名<占位符>{

    //占位符跟c语言中的打印printf很像,比如printf(“%d”,a);

    //相当于帮要打印的a占了个位置

}

main方法中的应用:

类名<类型>  引用名 = new 类名<>();

实例:

class MyArray2<E>{   //E相当于占位符
    public Object[] objects = new Object[10];

    public void setObjects(int pos,E a){ 
        this.objects[pos] = a;     
    }
    public E getObjects(int pos){
        return (E)objects[pos];
    }
}

MyArray2<Integer> myArray2 = new MyArray2<>();

此时,我们的myArray2这个引用指向的Object类型的数组就只能存int类型的整数了,E是我随便取的名字,一般用来表示Element,相当于帮Integer占了个位置,虽然数组类型还是Object类型,但此时我用起来的感觉就是Integer类型,这样我们就可以创建多个对象,每个引用指向的数组存放不同类型的数据,做到分工明确,而不是一股脑一个数组里放各种类型的数据,这就是泛型的好处。

三、对泛型的约束

1.由于泛型太过死板,我们需要再类型安全和代码复用性之间找到平衡,就需要对泛型做一定约束

语法:

class  MyArray3<E extends Number>{  //对泛型做一定约束,规定传入参数E是Number类型或者是Number子类的类型

这样我们就规定MyArray3类型的引用存放的对象类型一定要是Number类型或是其子类类型的数据

2.假设此时我有这样一个类

class Alg<E >{
    public E findMax(E[] array){
        E max = array[0];
        for (int i = 0; i < array.length; i++) {
            if(max<array[i]){  //这里报错,是因为我们不知道E是什么类型,更不知道到时候E的类型是否可比较,不知道到时候传进来的E是否实现Compare接口
                max = array[i];
            }
        }
        return max;
    }
}

我们发现系统报错,为什么呢,我们不知道到时候规定的类型E的比较规则是什么,可不可以比较也不知道,为什么就敢直接用 <,>,=比较呢,所以我们有另一种约束方法:

class Alg<E extends Comparable<E>>{
    public E findMax(E[] array){
        E max = array[0];
        for (int i = 0; i < array.length; i++) {
            if(max.compareTo(array[i])<0){ 
                max = array[i];
            }
        }
        return max;
    }
}

我们约束,传入的参数E一定要是实现过Comparable接口的,这样E类型就一定会有compareto这个方法了,我们也可以进行比较了

四、泛型方法

语法:

class Alg2{
    public<E extends Comparable<E>> E findMax(E[] arr){ //泛型方法  还可以在public后面加 static做到不创建对象直接调用方法
        E max = arr[0];
        for (int i = 0; i <arr.length ; i++) {
            if(max.compareTo(arr[i])<0){
                max = arr[i];
            }
        }
        return max;
    }
}

此时我们创建对象后引用这个方法,传入数组后,它会自动检查我传入的数组的类型是否实现过Comparable接口,如果没实现则会报错,如果实现,则会自动识别该数字的类型并进行比较

public static void main(String[] args) {
    Alg2 alg2 = new Alg2();
    Integer[] arr = {1,2,9,8,55,68,4};
    int ret = alg2./*<Integer>*/findMax(arr); //写不写都行,其会根据数组来推断是什么类型
    System.out.println(ret);
}

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐