Java 泛型中的通配符 T,E,K,V是什么

前言

不久前,被人问到Java 泛型中的通配符 T,E,K,V,? 是什么?有什么用?这不经让我有些回忆起该开始学习Java那段日子,那是对泛型什么的其实有些迷迷糊糊的,学的不这么样,是在做项目的过程中,渐渐有又看到别人的代码、在看源码的时候老是遇见,之后就专门去了解学习,才对这几个通配符 T,E,K,V,?有所了解。

泛型有什么用?

在介绍这几个通配符之前,我们先介绍介绍泛型,看看泛型带给我们的好处。
Java泛型是JDK5中引入的一个新特性,泛型提供了编译是类型安全检测机制,这个机制允许开发者在编译是检测非法类型。泛型的本质就是参数化类型,就是在编译时对输入的参数指定一个数据类型。

  • 类型安全:编译是检查类型是否匹配,避免了ClassCastexception的发生。
  // 非泛型写法(存在类型转换风险)
  List list1 = new ArrayList();
  list1.add("a");
  Integer num = (Long) list1.get(0);  // 运行时抛出 ClassCastException

  // 泛型写法(编译时检查类型)
  List<String> list2 = new ArrayList<>();
  // list.add(1);       // 编译报错
  list2.add("a");
  String str = list2.get(0); // 无需强制转换 
  • 消除代码强制类型转换:减少了一些类型转换操作。
// 非泛型写法
Map map1 = new HashMap();
map1.put("user", new User());
User user1 = (User) map1.get("user");

// 泛型写法
Map<String, User> map2 = new HashMap<>();
map2.put("user", new User());
// 自动转换
User user2 = map2.get("user");
  • 代码复用:可以支持多种数据类型,不要重复编写代码,例如:我们常用的统一响应结果类。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
    /**
     * 响应状态码
     */
    private int code;

    /**
     * 响应信息
     */
    private String message;

    /**
     * 响应数据
     */
    private T data;

    /**
     * 时间戳
     */
    private long timestamp;
    其他代码省略...
  • 增强可读性:通过类型参数就直接能看出要填入什么类型。
  • 泛型里的通配符

    我们在使用泛型的时候,经常会使用或者看见多种不同的通配符,常见的 T,E,K,V,?这几种,相信大家一定不陌生,但是真的问你他们有什么作用?有什么区别时,很多人应该是不能很好的介绍它们的,接下来我就来给大家介绍介绍。

    T,E,K,V

  • T(Type) T表示任意类型参数,我们举个例子
    pubile class A<T>{
        prvate T t;
        //其他省略...
    }
    
    //创建一个不带泛型参数的A
        A a = new A();
        a.set(new B());
        B b = (B) a.get();//需要进行强制类型转换
    
    //创建一个带泛型参数的A
        A<B> a = new A<B>();
        a.set(new B());
        B b = a.get();
    

  • E(Element) E表示集合中的元素类型
    List<E> list = new ArrayList<>();
    

  • K(Key) K表示映射的键的数据类型
    Map<K,V> map = new HashMap<>();
    

  • V(Value) V表示映射的值的数据类型
    Map<K,V> map = new HashMap<>();
    

    通配符 ?

  • 无界通配符 <?> 表示未知类型,接收任意类型
       // 使用无界通配符处理任意类型的查询结果
       public void logQueryResult(List<?> resultList) {
           resultList.forEach(obj -> log.info("Result: {}", obj));
       }
    

  • 下界通配符 <? super T> 表示类型是T或者是父类
      // 使用下界通配符写入缓存
       public void setCache(String key, <? super Serializable> value) {
           redisTemplate.opsForValue().set(key, value);
       }
    

总结

我们在很多时候只是单纯的会使用某些技术,但是对它们里面许许多多常见的都是一知半解的,只是会使用确实很重要,但是如果有时间,我们不妨好好的在对这些技术进行深入学习,不仅知其然,而且知其所以然,这样我们的技术才会不断提升进步。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值