• 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html
  • 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html

Java泛型的局限和使用经验

技术杂谈 勤劳的小蚂蚁 2个月前 (02-09) 65次浏览 已收录 0个评论 扫描二维码

泛型的局限

  1. 任何基本类型不能作为类型参数
    经过类型擦除后,List中包含的实际上还是Object的域,而在Java类型系统中Object和基本类型是两套体系,需要通过“自动装包、拆包机制”来进行交互。
    public class ListOfInt {

       public static void main(String[] args) {
           //(1)通过自动装包和拆包,在泛型中和基本类型进行交互
           List<Integer> li = new ArrayList<>();
           for (int i = 0; i < 5; i++) {
               //发生自动装包
               li.add(i);
           }

           //发生自动拆包
           for (int i: li) {
               System.out.println(i);
           }

           //(2)错误示例
           List<int> list = new ArrayList<>();
       }
    }

  2. 任何在运行时需要知道确切类型信息的操作都无法工作。
    由于Java的泛型是编译期泛型(在进入运行时后没有泛型的概念),因此运行时的类型转换和类型判定等操作都没有效果。
    public class Erased<T> {

       public void f(Object[] args) {
           //(1)不能在类型参数上使用instanceof操作, instanceof右边必须是某个原生类型或数组
           if (args instanceof T) {}

           //(2)不能直接实例化类型参数
           T var = new T();

           //(3)不能这么定义泛型数组,原因同上
           T[] array = new T[100];

           //(4)先定义一个Object数组,再强转成T[]数组,绕过泛型检查,但是会收到一个告警
           T[] array2 = (T[])new Object[100];
       }
    }

  3. 冲突1:方法名一样,参数列表是同一个类型参数的两个泛型方法,重载将产生相同的函数签名;
    package org.java.learn.generics;

    import java.util.List;

    public class UserList<W, T> {
       void f(List<T> v) {}
       void f(List<W> v) {}
    }
    从图中的提示可以看出,在泛型擦除后,这两个方法签名完全相同,产生冲突;
  4. 冲突2:使用泛型接口时,需要避免重复实现同一个接口
    interface Payable<T> {}

    class Employee implements Payable<Employee> {}

    class Hourly extends Employee implements Payable<Hourly> {}
    IDEA编辑器给出如下所示——“Payable不能被不同的类型参数继承,即不能重复实现同一个接口”

  5. 不能在静态域或方法中引用类型参数
    public class Erased<T> {

       public static void f(Object[] args) {
           //不能在静态域中引用类型参数
           if (args instanceof T) {}

           T var = new T();

           T[] array = new T[100];

           T[] array2 = (T[])new Object[100];
       }
    }
    这个例子跟问题2基本相同,唯一是在方法的签名里多了一个static关键字,然后引发编译错误的原因就变成了:在静态域中无法引用类型变量(入下图所示)。

泛型的常用经验

  1. 尽量消除异常,初学者容易写出使用原生类型的代码,或者使用泛型不当的代码,现在编辑器非常先进,尽量消除提示的异常;对于开发者自己确认不需要消除切可以工作的代码,可以使用@SuppressWarnings(“unchecked”)屏蔽掉异常;
  2. 能用泛型类(或接口)的时候尽量使用;能用泛型方法的时候尽量使用泛型方法;
  3. 定义API时,尽量使用泛型;
    public class PlainResult<T> extends BaseResult {
       private static final long serialVersionUID = -xxxxxx;

       private T data;

       public PlainResult() {
       }

       public T getData() {
           return this.data;
       }

       public void setData(T data) {
           this.data = data;
       }
    }

  4. 编写基础工具类时,尽量使用泛型;
    //使用泛型类
    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public class DataListPageInfo<T> {
       int page;
       int pageSize;
       int totalCount;
       List<T> items = new ArrayList<>();

    }
    @Component
    public class RedisTemplateService {

       private static final Logger LOGGER = LoggerFactory.getLogger(RedisTemplateService.class);

       @Resource
       private RedisTemplate redisTemplate;

       private String getKey(String key, Object… params) {
           if (params == null || params.length <= 0) {
               return key;
           }

           return String.format(key, params);
       }

        //这里使用了泛型方法
        public <T> T getFromJsonCache(Class<T> type, String keyPrefix, Object… params) {
           try {
               String ret = getString(keyPrefix, params);
               return JSON.parseObject(ret, type);
           } catch (Exception e) {
               LOGGER.error(“json parse error, type={},keyPrefix={},params={}”, type, keyPrefix, params, e);
           }

           return null;
       }

        ……  
    }

    • 例子2:缓存操作工具类,这里使用了
    • 例子1:通用的返回值对象

参考资料

  1. 《Java编程思想》
  2. 《Java核心技术》
  3. 《Effective Java》


丨极客文库, 版权所有丨如未注明 , 均为原创丨
本网站采用知识共享署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议进行授权
转载请注明原文链接:Java泛型的局限和使用经验
喜欢 (0)
[247507792@qq.com]
分享 (0)
勤劳的小蚂蚁
关于作者:
温馨提示:本文来源于网络,转载文章皆标明了出处,如果您发现侵权文章,请及时向站长反馈删除。

您必须 登录 才能发表评论!

  • 精品技术教程
  • 编程资源分享
  • 问答交流社区
  • 极客文库知识库

客服QQ


QQ:2248886839


工作时间:09:00-23:00