我正在开发一个类似于JTable的setDefaultRenderer
方法的类。我想要Class
- 特定的格式化程序,它将对象转换为适合显示的字符串。
public interface Formatter<T> {
String format(T value);
}
private Map<Class<?>, Formatter<?>> formatters;
public <T> void addFormatter(Formatter<T> formatter) {
formatters.put(T.class, formatter);
}
这就是我现在的代码,但Java不接受T.class
。
error: cannot select from a type variable
formatters.put(T.class, formatter);
^
1 error
有没有办法在不传递单独的Class<T>
参数的情况下编写此内容?我试图避免这种情况。这似乎是多余的。
答案 0 :(得分:5)
不,由于Java中的通用type erasure,这是不可能的。有关泛型类的所有信息都在运行时丢失,唯一的解决方案是明确地将类作为参数传递。
答案 1 :(得分:1)
由于type-erasure T.class
在运行时不可用,因此您必须传入一个单独的参数。通常,泛型类型信息在运行时不可用(除非您使用的是无界通配符)。
答案 2 :(得分:1)
Java语言不可能。所有泛型类型都在编译时确定,因此您无法在执行时访问类值。因此,您还需要传递Class<T>
参数才能访问它。
public Class MyGenericClassContainer<T>{
public T instance;
public Class<T> clazz;
public MyGenericClassContainer(Class<T> clazz){
intance = clazz.newInstance();
}
}
答案 3 :(得分:1)
一般来说,这是不可能的。但是,在您的情况下,让Formatter
实施Class<T> getFormatterTargetClass()
方法可能是合理的,然后您可以在代码中使用T.class
代替{{1}}。
答案 4 :(得分:1)
不是解决方案,而是黑客攻击。
你可以做到。但通过肮脏的技巧和反思。以下面的代码为例。礼貌here:
class ParameterizedTest<T> {
/**
* @return the type parameter to our generic base class
*/
@SuppressWarnings("unchecked")
protected final Class<T> determineTypeParameter() {
Class<?> specificClass = this.getClass();
Type genericSuperclass = specificClass.getGenericSuperclass();
while (!(genericSuperclass instanceof ParameterizedType) && specificClass != ParameterizedTest.class) {
specificClass = specificClass.getSuperclass();
genericSuperclass = specificClass.getGenericSuperclass();
}
final ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
final Type firstTypeParameter = parameterizedType.getActualTypeArguments()[0];
return (Class<T>) firstTypeParameter;
}
}
//change the type of PrameterizedTest<Integer> to Parameterized<String> or something to display different output
public class Test extends ParameterizedTest<Integer>{
public static void main(String... args){
Test test = new Test();
System.out.println(test.determineTypeParameter());
}
}
在运行时,您将获得Type参数。因此,在您的课程中,您必须定义一个Class
对象,如上所述获取该类。然后使用Class.newInstance
获得一个新对象。但是你必须手动处理类型转换等等。
问题是:这一切都值得吗?
根据我的说法,通过使用泛型类型中的边界并连接到绑定类型,可以避免大部分内容。所以你应该寻找替代解决方案
答案 5 :(得分:1)
一个有益的练习就是问自己,“如果没有仿制药,我该怎么做?”答案也是你问题的答案。
通过删除泛型并在正确的位置插入强制转换,可以将具有泛型的程序写入没有泛型的等效程序,而无需更改代码中的任何其他内容。这种转换称为“类型擦除”。这意味着如果没有泛型就无法写出某些内容,那么它也不能用泛型来编写。
如果没有泛型,您的代码如下所示:
public interface Formatter {
String format(Object value);
}
private Map formatters;
public void addFormatter(Formatter formatter) {
formatters.put(?, formatter);
}
所以,我问你,你会怎么做?