V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
abcbuzhiming
V2EX  ›  Java

这样的泛型定义到底如何调用才是对的呢?

  •  
  •   abcbuzhiming · 2018-01-02 21:05:28 +08:00 · 2500 次点击
    这是一个创建于 2551 天前的主题,其中的信息可能已经有所发展或是发生改变。
    public class Abc<T>{
         private final JavaType javaType;
         public Abc(Class<T> type) {
    		this.javaType = getJavaType(type);
    	}
    }
    
    

    我调用的时候

    Abc<HashSet<String>> Abc = new Abc<HashSet<String>>(HashSet<String>.class);
    

    通不过,报错

    Abc<HashSet<String>> Abc = new Abc<HashSet<String>>(HashSet.class);
    

    还是报错

    Abc<HashSet> Abc = new Abc<HashSet>(HashSet.class);
    

    这样终于可以了,但是没有指定 HashSet 容器内部的类型,IDE 报警,而且我也觉得这好像不是正统的 java 写法,正统的 java 写法都应该指定容器里的类型的。

    我查了不少资料,看起来最后一种才是对的,但是为啥最后一种那么别扭呢

    12 条回复    2018-01-03 20:55:43 +08:00
    lhx2008
        1
    lhx2008  
       2018-01-02 21:16:43 +08:00
    这个应该是泛型的类型擦除导致的吧,Class 是没有泛型的,HashSet<String>的 Class 是 HashSet 不是 HashSet<String>
    abcbuzhiming
        2
    abcbuzhiming  
    OP
       2018-01-02 21:26:34 +08:00
    @lhx2008 我知道 java 这玩意存在泛型擦除问题,但是奇怪的是,第二种写法也不对,第三种对了吧,但是 IDE 会报警说你没给容器指定元素的类型,感觉也不正统,所以我想知道这里正统的想法到底是啥
    lhx2008
        3
    lhx2008  
       2018-01-02 21:50:21 +08:00
    @abcbuzhiming
    IDE 报警用 @SuppressWarnings("unchecked")抑制就好,或者把 Class<T>的<T>去掉
    因为 HashSet<String>.class 的写法是语法错误的,所以只能写 HashSet.class,Class 是 HashSet
    然后,
    T 就是 HashSet,不是 HashSet<String>了,所以要 Abc<HashSet>
    zhx1991
        4
    zhx1991  
       2018-01-02 22:15:12 +08:00
    感觉你需要的是 ? 而不是 T
    abcbuzhiming
        5
    abcbuzhiming  
    OP
       2018-01-02 22:21:25 +08:00
    @lhx2008 那为什么第二写法是错的呢?
    Abc<HashSet<String>> Abc = new Abc<HashSet<String>>(HashSet.class);
    icegreen
        6
    icegreen  
       2018-01-02 22:24:19 +08:00
    如果你更关心容器内部的类型, 就把 String 当做参数传进去吧. 或者传 HashSet 和 String 两个参数?

    不了解业务场景, 无法给出准确建议~~.
    abcbuzhiming
        7
    abcbuzhiming  
    OP
       2018-01-02 22:31:17 +08:00
    @icegreen 你没弄懂我的意思,这无关业务场景,而是 java 的泛型参数到底该如何使用的问题,如果我传入的是一个容器类型该如何使用,java 本身都是推荐在使用容器类型是指明容器元素类型的,但是这里明显有矛盾
    finull
        8
    finull  
       2018-01-02 23:03:55 +08:00
    只用过 C# 的泛型,不理解这个类名称定义中已经有`T`了,为什么还要在构造函数中再穿个`Class<T>`进去
    iEverX
        9
    iEverX  
       2018-01-02 23:12:26 +08:00
    @abcbuzhiming 因为 HashSet<String> 和 HashSet 的类型不一样啊
    iEverX
        10
    iEverX  
       2018-01-02 23:13:21 +08:00
    类似的需求,可以用 TypeReference
    zjp
        11
    zjp  
       2018-01-03 10:50:29 +08:00
    @finull Java 泛型的实现里用了类型擦除,想要在运行时知道泛型的类型就得自己保存
    SoloCompany
        12
    SoloCompany  
       2018-01-03 20:55:43 +08:00
    因为类型擦除, 所有 concret type 的 Class<T> 中的 T 只能是 raw type
    数组也有类似的限制: new T[] 中的 T 也只能是 raw type
    如果你需要 parameterized type 的 class object 或数组, 只能靠 upcast

    比如
    List<String>[] list = new List[]; // new List<String>[] 是非法的
    Class<List<String>> classOfListOfString = List.class; // List<String>.class 当然也是非法的

    前者 (parameterized array) 有一定意义, 后者基本上毫无意义
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2674 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 12:00 · PVG 20:00 · LAX 04:00 · JFK 07:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.