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
这样的好处显而易见,使用一个类就可以处理不同类型的元素
// 创建可以存储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
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;
}
}
静态方法
静态方法不能引用泛型类型
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 {}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!