三、泛型

# 三、泛型

# 1、什么是泛型?作用是什么?

Java 泛型(Generics) 是 JDK 5 中引入的一个新特性。
泛型是一种参数化类型的机制,它允许在定义类、接口和方法时使用类型参数。通过泛型,可以编写与特定类型无关的代码,使得代码具有更广泛的适用性和重用性。

具体体现在以下方面

  • 类型安全:泛型通过在编译时进行类型检查,可以在编译阶段发现类型不匹配的问题,减少了运行时出现类型转换异常的可能性,提高了程序的健壮性。
  • 代码重用: 通过使用泛型,可以编写更加通用的算法和数据结构,使得它们可以适应不同的数据类型,从而提高了代码的重用性。
  • 简化编码: 使用泛型可以减少重复代码的编写,提高代码的可读性和可维护性。你可以编写一个泛型类或方法,在需要时指定具体的类型参数,
    而不需要为每种类型都编写一个新的类或方法。
  • 性能提升: 泛型在编译时会执行类型擦除(Type Erasure)以确保向后兼容性,这种擦除可以提高代码执行时的性能。

例如: 编写一个盒子类 使用泛型 允许向盒子内添加任何类型

public class Box<T> {
    private T content;

    public Box(T content) {
        this.content = content;
    }

    public T getContent() {
        return content;
    }

    public void setContent(T content) {
        this.content = content;
    }

    public void printContentType() {
        System.out.println("盒子里装的是:" + content.getClass().getName());
    }
}

再比如集合中使用的泛型

ArrayList<User> userList = new ArrayList<>();

规定集合中只能存放User类型 以确保类型安全和编码的清晰性

# 2、泛型的使用方式有哪些?

泛型一般的使用方式:

  • 泛型类
  • 泛型接口
  • 泛型方法
  • 类型通配符

泛型类示例:
代码中的T 表示泛型 可以用任意的大小写字母代替 建议使用 T、V、K等字符

class Box<T>{
    T data;

    public Box(T data) {
        this.data = data;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
    
    public void printData(){
        System.out.println(data.toString());
    }
}

泛型接口示例:

public interface BaseMapper<T> {
    public T get(String id);
}

// 实现泛型接口 指定类型
public class MyMapper<T> implments BaseMapper<User>{
   	@Override
    public User get(String id){
		retrun new User();
    }
}

// 实现泛型接口 不指定类型
public class MyMapper<T> implments BaseMapper<T>{
   	@Override
    public T get(String id){
		retrun null;
    }
}

泛型方法:

public static <K extends Comparable, V extends Comparable> Map<K, V> sortMapByValues(Map<K, V> aMap,long limitSize) {
    HashMap<K, V> finalOut = new LinkedHashMap<>();
    aMap.entrySet()
            .stream()
            // 排序
            .sorted((p1, p2) -> p2.getValue().compareTo(p1.getValue()))
            // 截取前limitSize个
            .limit(limitSize)
            .collect(Collectors.toList()).forEach(ele -> finalOut.put(ele.getKey(), ele.getValue()));
    return finalOut;
}

类型通配符示例:

  • 类型通配符:<?>
    List<?>:表示元素类型未知的List,它的元素可以匹配任何的类型
    这种带通配符的List仅表示它是各种泛型List的父类,并不能把元素添加到其中

  • 类型通配符上限:<? extends 类型>
    List<? extends Number>:它表示的类型是Number或者其子类型

  • 类型通配符下限:<? super 类型>
    List<? super Number>:它表示的类型是Number或者其父类型

    举例:

// 这里的返回值 必须是 BaseRowModel类型 或者其子类型
public static <T extends BaseRowModel> ExcelWriterFactory writeExcelWithSheets(OutputStream outputStream,
                                                                                   Class<T> clazz) {
        return new ExcelWriterFactory(outputStream, clazz);
    }

# 3、项目中哪些地方使用到了泛型?

①、Mybatis的通用Mapper接口

public interface QguBaseMapper<T extends BaseModel> extends Mapper<T> {
}

②、通用的持久化接口

public interface MybatisService<T extends BaseModel> extends BaseService<T> {

    Page<T> search(T model, Page<T> pageInfo, String... orders);

    Page<T> search(Example example, Page<T> pageInfo, String... orders);
}

通用的导出功能抽象类

public abstract class AbstractBaseExportServiceImpl<T extends BaseModel> extends BaseServiceImpl<T> implements BaseExportService<T> {
// ...
}

③、各种通用的Util工具

总而言之 如果想让代码获得良好的重用性 使用泛型是一个非常重要的手段