如何在Java中实现`MyClass<String>.class`?

17
如何使用 MyClass<String>.class 作为 clazz 调用 public <T> T doit(Class<T> clazz); 方法,而我不能实例化或扩展 MyClass。
编辑:'David Winslow' 和 'bmargulies' 的回答是正确的 (MyClass<String>) doit(MyClass.class); 对于原始问题可以工作,但令人惊讶的是,当该方法返回 MyClass<T> 而不是 T 时,强制类型转换将不再编译。
编辑:我已经将 List 替换为 MyClass,并添加了我的原始问题的条件。

@Bozho 看一下更新。我简化了我的真实情况。 - Ali Shakiba
6个回答

14
使用 List.class。由于 类型擦除,Java 类型参数完全是编译时构造的 - 即使 List<String>.class 是有效语法,它也会是与 List<Date>.class 相同的类。由于反射本质上是运行时操作,它不能很好地处理类型参数(在 Java 中实现)。
如果您想使用 Class 对象来实例化一个新的 List 实例,您可以将该操作的结果强制转换为具有适当类型参数的类型。
List<String> list = (List<String>)(ArrayList.class.newInstance());

1
“不能这样做”不是描述技术问题的好方式。代码能否编译?运行时是否出现错误?每次尝试编译时是否有人来拿走你的键盘? - David Winslow
是的,我错了,我删除了我的评论。我还有另一个错误,我仍在努力工作。 - Ali Shakiba

9

我已经看到很多类似的问题被问过,例如获取泛型类类型

构建静态泛型类型是有合法理由的。在op的情况下,他可能会想要这样做。

MyClass<String> result = doit(MyClass<String>.class);

没有语言语法支持,强制类型转换是正确的方式。如果这种情况经常出现,则应将强制类型转换放入方法中,如

public class MyClass<T>
{
    @SuppressWarnings("unchecked")
    // may need a better method name
    static public <T2> Class<MyClass<T2>> of(Class<T2> tClass)
    {
        return (Class<MyClass<T2>>)(Class<?>)(MyClass.class);
    }
}

MyClass<String> result = doit(MyClass.of(String.class)); // no warning

我们可以在确保强制转换安全后,仅对该方法抑制警告。任何调用该方法的地方都不会看到警告。
这是一个编译时强制转换的游戏。在运行时,所有类型参数都被擦除,实际上只有裸类对象在传递。of方法很可能被优化掉,因此对于JVM来说,最后一行什么都不是。
MyClass result = doit(MyClass.class)

有时候在运行时我们需要一个完整的MyClass<String>类型。需要获取一个ParameterizedType对象来表示MyClass<String>

当这两个要求结合在一起时,也就是说,我们需要一个关于MyClassString的编译时表达式,在运行时评估为一个ParameterizedType

ParameterizedType type_MyClass_String = ???? MyClass ?? String ???

有一种技术涉及到 MyClass<String> 的一个匿名子类。

ParameterizedType type_MyClass_String = superTypeOf( new MyClass<String>(){} );

我发现这相当令人不安。

1
你是不是想要 return (Class<MyClass<T2>>) (Class<?>) MyClass.class; - Ali Shakiba

2
请参阅http://jackson.codehaus.org/1.7.0/javadoc/org/codehaus/jackson/type/TypeReference.html以及它所引用的参考文献,全面讨论与泛型相关的问题。 总之,如果您真的想以这种方式使用通用类型,就必须停止使用Class并开始使用Type及其子类。 与您在另一个答案中的评论相反,您可以编写List<List<String>> obj = (List<List<String>>) doit(List.class);,但编写时无法避免警告。

1

自从你的更新后,你的问题似乎不是一个精确的重复

你需要在MyClass的实例上调用getClass()。最好在某个地方拥有一个虚拟的静态终态实例:

public static final MyClass INSTANCE = new MyClass();
...
return (Class<MyClass<String>>) instance.getClass();

无法将 Class<List> 转换为 List<String>。 - Ali Shakiba
无法将Class<List>转换为Class<List<String>>。 - Ali Shakiba
@JohnS 但是有什么阻止你实例化它的呢? - Bozho
最终类 MyClass<T> { private MyClass() { }public static MyClass create(Class clazz) { /*过于简化*/ return new MyClass(); }} - Ali Shakiba
@JohnS - 反射?还是使用工厂模式和 create(Object.class) 方法? - Bozho

0

T 对应于 List,因此任何将 String 作为 List 的泛型参数的引用都是不相关的。


-1
如何在Java中执行MyClass<String>.class
你不能这样做。
Java中的泛型使用类型擦除;编译时强制执行参数化参数的类型,但在编译,它会丢失。泛型类的实例的结果字节码不包含任何关于其参数的运行时元数据。
目前来看,这是不可能的,这是一个重大的语言设计失误,在我看来。

你是否知道 ParameterizedType 的存在? http://download.oracle.com/javase/1.5.0/docs/api/java/lang/reflect/ParameterizedType.html - Ali Shakiba
ParameterizedType 在我看来是一个欺骗,它在语法和语义上与像 X.class 这样的任意类或接口的求值不同。默认情况下,可以调用 X.class 而不必担心运行时或已检查异常。另一方面,ParameterizedType 只能与扩展泛型类(即 class StringList extends ArrayList<String>)的类一起使用。然后,JVM 可以跟踪继承的泛型参数类型,但否则不会。此外,在使用它时还必须处理潜在的异常。不一样。 - luis.espinal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接