每天学一点之泛型真不难

泛型

泛型即为“类型参数”,这个类型参数在声明它的类、接口或方法中,代表未知的通用的类型。

java.lang.Comparable接口和java.util.Comparator接口不确定是什么类型的对象比较大小,之前的时候只能用Object类型表示,使用时既麻烦又不安全,因此JDK1.5就给它们增加了泛型。

public interface Comparable<T>{
    int compareTo(T o) ;
}
public interface Comparator<T>{
     int compare(T o1, T o2) ;
}

其中就是类型参数,即泛型。

泛型的相关术语

<数据类型>这种语法形式就叫泛型。其中数据类型只能是引用数据类型。

  • TypeVariable:类型变量,例如:ArrayList<E>中的E,Map<K,V>中的K,V
  • ParameterizedType:参数化类型,例如:Comparator<T>Comparator<String>
  • GenericArrayType:泛化的数组类型,即T[]
  • WildcardType:通配符类型,例如:Comparator<?>

在哪里可以声明类型变量<T>

  • 声明类或接口时,在类名或接口名后面声明类型变量,我们把这样的类或接口称为泛型类或泛型接口
【修饰符】 class 类名<类型变量列表>extends 父类】 【implements 父接口们】{
    
}
【修饰符】 interface 接口名<类型变量列表>implements 父接口们】{
    
}

例如:
public class ArrayList<E>    
public interface Map<K,V>{
    ....
}   
  • 声明方法时,在【修饰符】与返回值类型之间声明类型变量,我们把声明(是声明不是单纯的使用)了类型变量的方法称为泛型方法
【修饰符】 <类型变量列表> 返回值类型 方法名(【形参列表】)throws 异常列表】{
    //...
}

例如:java.util.Arrays类中的
public static <T> List<T> asList(T... a){
    ....
}
  • <类型变量列表>:可以是一个或多个类型变量,一般都是使用单个的大写字母表示。例如:<T><K,V> 等。

  • 当类或接口上声明了<类型变量列表>时,其中的类型变量不能用于静态成员上。

  • //public static void test(T t){ } //此时类型变量T不能用在静态成员上

  • 当使用参数化类型的类或接口时,如果没有指定泛型,相当于Object类型。

案例:定义MyArrayList类
public class MyArrayList<T> {
    private Object[] all = new Object[4];
    private int total;

    public void add(T t){
        if(total >= all.length){
            all = Arrays.copyOf(all, all.length*2);
        }
        all[total++] = t;
    }

    public T get(int index){
        if(index<0 || index>=total){
            throw new IndexOutOfBoundsException(index +"越界");
        }
        return (T) all[index];
    }

    public Object[] toArray(){
        return Arrays.copyOf(all,total);
    }
}

类型通配符

 @Test
    public void test2() {
        //一、使用通配符?
        List<?> list;//泛型变量可以是任意类型
        list = new ArrayList<>();//泛型变量默认是Object类型的泛型
        list = new ArrayList<Object>();
        list = new ArrayList<String>();
        list = new ArrayList<Number>();
        list = new ArrayList<Integer>();

//        list.add(1);//compile error 编译器无法确定要add的真实类型,可能是<Character>或<Byte>,那么add(0.5)不可以,只有在方法被调用时才能确定。
        Object o = list.get(0);//无法确定元素类型,只能使用Object接收

        //二、设定通配符上限
        List<? extends Number> list1;//泛型变量必须是Number子类类型
        list1 = new ArrayList<>();//泛型变量默认是 Number类型
//        list1 = new ArrayList<Object>();//compile error
        list1 = new ArrayList<Number>();
        list1 = new ArrayList<Double>();

//        list1.add(1);//compile error 编译器无法确定要add的真实类型,可能是<Character>或<Byte>,那么add(0.5)不可以,只有在方法被调用时才能确定。
        Number number = list1.get(0);//可以使用Number接收,自动向上转型
        //所以设定了通配符上限,通常只能获取数据,即生产数据

        //三、设定通配符下限
        List<? super Number> list2;//泛型变量必须是Number父类类型
        list2 = new ArrayList<>();//泛型变量默认是 Number类型,
        list2 = new ArrayList<Object>();
        list2 = new ArrayList<Number>();
//        list2 = new ArrayList<Integer>();//compile error
        //
        list2.add(1.2);//编译器可以确定要add的真实类型一定是数值类型父类,那么add一个数值类型就不会有问题。
        Object object = list2.get(0);//返回值类型只能确定是Number的超类,编译器不确定具体类型,只能使用Object接收
        //所以设定通配符下限,通常用于添加数据,修改数据等即消费数据
    }

    //1.使用通配符,可以接收任意泛型的List集合
    public void handleList(List<?> list){
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(0));
        }
    }

    //2.设定通配符上限
    //定义一个方法,只能处理装有数值类型元素的List集合
    public void handleNumberList(List<? extends Number> list){
        double sum=0;
        for (Number number : list) {
            sum += number.doubleValue();
        }
        System.out.println(sum);
    }
    //3.设定通配符下限
    //定一个方法,需要一个比较器,只要能处理T类型数据的比较器就可以
    //比如要比较T[]的数组元素大小,那么就需要一个可以比较T类型元素或能比较T的父类型元素(一定能比较T)的比较器
    public <T> void  handleComparator(T[] arr,Comparator<? super T> c){

    }
    //3.1设定通配符下限
    //定义一个方法,可以向任意List集合中(泛型类型下限为T型的集合),添加T型元素(泛型类型下限为T型的集合一定可以添加T型元素)
    public static <T> void fill(List<? super T> list,T obj){
        for (int i = 0; i < list.size(); i++) {
            list.add(obj);
        }
    }

}

案例:
创建Student类

class Student implements Comparable<Student>, Comparator<Student> {
    private String name;
    private int age;
    省略get/Set、toString以及有参无参构造器
     @Override
    public int compareTo(Student o) {
        int i = age - o.getAge();
        return i == 0 ? name.compareTo(o.getName()) : i;
    }

    @Override
    public int compare(Student o1, Student o2) {
        int i = o1.getAge() - o2.getAge();
        return i == 0 ? o1.getName().compareTo(o2.getName()) : i;
    } 

编写工具测试类:

public class MyArrays {
    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("张山", 15);
        students[1] = new Student("李四", 18);
        students[2] = new Student("王五", 17);
        MyArrays.sort(students);
        for (Student s : students) {
            System.out.println(s);
        }
        MyArrays.sort(students, Student::compareTo);
        for (Student s : students) {
            System.out.println(s);
        }
        MyArrays.sort(students, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                int i=o1.getAge()-o2.getAge();
                return i==0?o1.getName().compareTo(o2.getName()):i;
            }
        });
        for (Student s:students) {
            System.out.println("s = " + s);
        }
    }

    public static <T extends Comparable<T>> void sort(T[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j].compareTo(arr[j + 1]) > 0) {
                    T temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

    public static <T> void sort(T[] arr, Comparator<T> c) {
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (c.compare(arr[j], arr[j + 1]) > 0) {
                    T temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }

            }
        }

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力奋斗的JAVA小余

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值