Java泛型

Java泛型

简介

在代码中发现了一个没见过没用过的写法,借此复习一下泛型。

public static <T> BaseResponseVo.BaseResponseVoBuilder<T> builder() {
        return new BaseResponseVo.BaseResponseVoBuilder<>();
    }

泛型实际上就是一种模板,从“如果没有泛型会发生什么”的角度来理解,比如经常使用的ArrayList类,如果不用泛型,那么对于类内部的数组只能用Object来修饰,在调用get方法是做强制转换,显然这是不安全的。

ArrayList list = new ArrayList();
list.add("Hello");
// 获取到Object,必须强制转型为String:
String first = (String) list.get(0);

如果我们不希望类型转换,那么对于每一种类型如String,Integer,Double等,都要分别写一个新的类StringArrayList,IntegerArrayList,DoubleArrayList,将类中的数组分别用String,Integer,Double来修饰,这样在调用get的时候就可以确定元素的类型。
然而,这样类的数量太多,也不方便记忆。

因此,Java提供了泛型的方案,将ArrayList变成了一种模板ArrayList,在实现类的时候将所有可能的类型抽象成T,在实例化的时候指定元素的类型。
这样的好处显而易见,使用一个类就可以处理不同类型的元素

// 创建可以存储String的ArrayList:
ArrayList<String> strList = new ArrayList<String>();
// 创建可以存储Float的ArrayList:
ArrayList<Float> floatList = new ArrayList<Float>();
// 创建可以存储Person的ArrayList:
ArrayList<Person> personList = new ArrayList<Person>();

向上转型

在Java代码的书写中,最经常使用的就是List<Integer> list = new ArrayList<>(),即泛型可以向上转型,因为ArrayList的实现是继承自List

public class ArrayList<T> implements List<T> {
    ...
}

但是,另外一种转型是不允许的,即把ArrayList转型为ArrayList

泛型接口

除了ArrayList使用了泛型,还可以在接口中使用泛型。例如,Arrays.sort(Object[])可以对任意数组进行排序,但待排序的元素必须实现Comparable这个泛型接口:

public interface Comparable<T> {
    /**
     * 返回负数: 当前实例比参数o小
     * 返回0: 当前实例与参数o相等
     * 返回正数: 当前实例比参数o大
     */
    int compareTo(T o);
}

比如使用频率较高的pair

class Pair<T> implements Comparable<Pair<T>> {
    T first;
    T second;
    Pair(T first, T second) {
        this.first = first;
        this.second = second;
    }

    @Override
    public int compareTo(Pair o) {
        return (int)this.d - (int)o.d;
    }
}

静态方法

静态方法不能引用泛型类型,必须定义其他类型(例如)来实现静态泛型方法(但实际上类和方法都写T也没事)

public class Pair<T> {
    private T first;
    private T second;
    public Pair(T first, T second) {
        this.first = first;
        this.second = second;
    }
    public T getFirst() { ... }
    public T getLast() { ... }

    // 静态泛型方法应该使用其他类型区分:
    public static <K> Pair<K> create(K first, K second) {
        return new Pair<K>(first, second);
    }
}

究其原因,是静态方法只能通过类来调用
Java的泛型方法属于伪泛型,在编译的时候将进行类型擦除
静态方法由于随着类的加载而加载,不能访问类的泛型(因为在创建对象的时候才确定),因此必须定义自己的泛型类型。
对于Pair<Integer> p = new Pair<>(),在执行的时候T的类型是明确的,但是如Pair.create(1, 2),但此时并不知道T的类型,只能通过多加一个泛型。
到这里就可以解答开篇的疑问了,builder方法是一个静态泛型方法,因此在static后要加一个<T>,在调用的时候,要像下面一样调用

    @ApiOperation(value = "...")
    @GetMapping("...")
    public BaseResponseVo<TaskListVO> getTodoList(@PathVariable Integer sortType,HttpServletRequest request){
        //TODO shiro获取session
        SessionUser sessionUser = (SessionUser)request.getSession().getAttribute("...");
        TaskListDTO taskListDTO = taskDomain.searchCompletedTaskList(sessionUser,sortType);
        MapperFacade mapperFacade = mapperFactory.getMapperFacade();
        TaskListVO result = mapperFacade.map(taskListDTO,TaskListVO.class);
        return BaseResponseVo.<TaskListVO>builder().success(result);
    }

extends和super

package com.example.demo;

import java.util.ArrayList;
import java.util.List;

public class test2 {

    public static Car testExtends(List<? extends Car> list) {
        // list的元素可能是Car或Car的子类,包括Car,Benz,Audi,BMW等
        // extends修饰的只能取,不能放
        // 不可以,因为Car的子类有很多,无法确定当前list的泛型是哪一种,可能是Car,Benz,Audi
        // list.add(new Car()); 报错
        // 同理
        // list.add(new Benz()); 报错
        Car car = list.get(0);
        return car;
    }

    public static Object testSuper(List<? super Car> list) {
        // list的元素可能是Car以及Car的所有父类,包括Vehicle,Car,Object等
        list.add(new E_Class()); // Car和Car的子类都没问题,但不能是Vehicle
        Object obj = list.get(0); // 用Car和Vehicle接收变量都是不行的,因为不能保证Car只有一个Vehicle父类
        return obj;
    }

    public static void main(String[] args) {
        List<Car> list = new ArrayList<>();
        list.add(new Car());
        list.add(new Car());
        Car car = testExtends(list);
        System.out.println(car);
        Object obj = testSuper(new ArrayList<Vehicle>());
        System.out.println(obj);
    }

}

class Vehicle {}
class Car extends Vehicle {}
class Benz extends Car {}
class Audi extends Car {}
class E_Class extends Benz {}
class A6 extends Audi {}
posted @   antidogmatist  阅读(173)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示