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

获取泛型 Class 问题

  •  
  •   yuxianjiazu · 2020-01-07 22:16:07 +08:00 · 4156 次点击
    这是一个创建于 1782 天前的主题,其中的信息可能已经有所发展或是发生改变。
    public class A<T> {
    
    }
    
    public class B {
    
        public static <T> get(Class<T> clazz) {
        	//...
        }
        
        public static void main(String[] args) {
        	System.out.println(get((A<String>).class));	// 1	错误写法
        }
    }
    

    请问,不添加

    class C extends A<String> {
    
    }
    

    的情况下, 怎么实现 1 的效果(C#可以实现,Java 不知道怎么实现)

    使用场景:A<t>里面的 T 可以是(D1, D2, ... Dn),不想分别多写一个(C1, C2, ... Cn)类
    A<(D1, D2, ... Dn)> 的 Class 是 B.get 的参数</t>

    第 1 条附言  ·  2020-01-07 22:59:30 +08:00
    public static <T> T get(Class<T> clazz)
    

    少写了返回值(。^▽^)

    实现的效果类似于 C# Type.MakeGenericType

    第 2 条附言  ·  2020-01-08 20:47:55 +08:00

    问题解决了哈(。^▽^)

    用了下面两个方法

    public class ParameterizedTypeImpl implements ParameterizedType {
    
        ParameterizedTypeImpl make(Class<?> var0, Type[] var1, Type var2) {
            return new ParameterizedTypeImpl(var0, var1, var2);
        }
    }
    

    public class ClassHelper {
    
        public static Type getGenericClass(Class<?> clazz) {
            return clazz.getGenericSuperclass()).getActualTypeArguments()[0];
        }
    }
    

    Map<Class<?>, Object> kvs 改成 Map<Type, Object> kvs B.get的参数也改成Type

    (基本就是Class<T>参数改成了Type,然后用上面的代码获取Type:A<T>)

    20 条回复    2024-06-26 18:19:04 +08:00
    Raymon111111
        1
    Raymon111111  
       2020-01-07 22:35:57 +08:00
    直接 get 的时候传 A.class 行吗?
    yuxianjiazu
        2
    yuxianjiazu  
    OP
       2020-01-07 22:37:41 +08:00 via Android
    @Raymon111111 不行的哦,需要返回 A<T>。
    lhx2008
        3
    lhx2008  
       2020-01-07 22:39:10 +08:00
    不能实现 1 的效果,A<t> 的话,用父类的泛型或者通配符泛型
    winterbells
        4
    winterbells  
       2020-01-07 22:40:04 +08:00
    我记得 Java 的泛型是编译时的,跑起来后就没 <T> 这个东西了
    kotlin 里有运行时的泛型,reified
    yuxianjiazu
        5
    yuxianjiazu  
    OP
       2020-01-07 22:40:14 +08:00
    ```
    public static <T> T get(Class<T> clazz)
    ```
    少写了返回值(。^▽^)
    Raymon111111
        6
    Raymon111111  
       2020-01-07 22:43:15 +08:00
    @yuxianjiazu get 完之后强转 A<T>
    des
        7
    des  
       2020-01-07 22:44:50 +08:00 via Android
    @winterbells
    确实 java 的泛型是编译时的,拿出来的是 object
    C#是运行时的
    yuxianjiazu
        8
    yuxianjiazu  
    OP
       2020-01-07 22:45:07 +08:00
    @Raymon111111 这样肯定不行的。。。返回的值是根据传入的 Class 进行运算的
    mxalbert1996
        9
    mxalbert1996  
       2020-01-07 23:12:23 +08:00 via Android
    关键词 type erasure。
    @winterbells Kotlin 的 reified 一样是编译时的,想想为什么它只支持 inline fun。
    yuxianjiazu
        10
    yuxianjiazu  
    OP
       2020-01-07 23:26:59 +08:00
    @mxalbert1996
    @des
    @winterbells
    @lhx2008
    @Raymon111111

    谢谢,了解了,还以为可以跟 C#一样。我还是把 D1, D2, ... Dn 写出来吧(;´д`)ゞ
    SoloCompany
        11
    SoloCompany  
       2020-01-07 23:52:06 +08:00 via iPad
    可以改一下方法签名

    public static <C, T> T get(Class<C> type, Class<T> genericType)

    get(A.class, String.class)
    guyeu
        12
    guyeu  
       2020-01-08 00:09:47 +08:00
    把参数的类型从 Class 改成 ParamizedType 即可。
    yuxianjiazu
        13
    yuxianjiazu  
    OP
       2020-01-08 01:16:57 +08:00 via Android
    @guyeu 是 ParameterizedType 吗,我看看哈。
    guyeu
        14
    guyeu  
       2020-01-08 12:38:35 +08:00
    @yuxianjiazu #13 啊是的,我拼错了。。。
    Aresxue
        15
    Aresxue  
       2020-01-08 13:34:21 +08:00
    泛型擦除,编译器不保留泛型信息,只能自己强转
    okhowang
        16
    okhowang  
       2020-01-08 14:19:07 +08:00
    可以参考 jackson 的泛型逻辑,传进去一个匿名泛型类
    mapper.readValue(jsonString, new TypeReference<Data<String>>() {});
    SoloCompany
        17
    SoloCompany  
       2020-01-08 18:15:30 +08:00 via iPhone
    @okhowang 你这里的 data 和 string 都是编译期存在运行时没有的
    yhvictor
        18
    yhvictor  
       2020-01-08 18:37:29 +08:00 via iPad
    可以用 guava 的 typetoken
    yuxianjiazu
        19
    yuxianjiazu  
    OP
       2020-01-08 20:50:51 +08:00
    Java 的 ParameterizedTypeImpl.make 类似于 C#的 Type.MakeGenericType
    codingbody
        20
    codingbody  
       150 天前
    @yuxianjiazu
    public class A<T> {

    public static Type getGenericClass(Class<?> clazz) {
    return ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
    }

    public static void main(String[] args) {
    A<List<String>> a = new A<>() {};
    System.out.println("Generic type: " + getGenericClass(a.getClass())); // 输出: Generic type: java.util.List<java.lang.String>
    }
    }

    这里必须用 new A<>() {} 这种匿名内部类的方式吧,这也就是 @okhowang 提到的 jackson 的实现方式。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1089 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 23:29 · PVG 07:29 · LAX 15:29 · JFK 18:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.