1

I am working on a class that will have functionality similar to JTable's setDefaultRenderer method. I want to have Class-specific formatters which convert objects to strings suitable for displaying.

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);
}

That's the code I have right now, but Java doesn't accept T.class.

error: cannot select from a type variable
        formatters.put(T.class, formatter);
                        ^
1 error

Is there a way to write this without passing a separate Class<T> parameter? I'm trying to avoid that. It seems redundant.

4

6 回答 6

6

不,这是不可能的,因为 Java 中的泛型类型擦除。有关泛型类的所有信息在运行时都会丢失,唯一的解决方案是将类作为参数显式传递。

于 2013-07-24T18:14:51.740 回答
1

不是解决方案,而是 hack。

你能行的。但是通过肮脏的伎俩和反思。例如看下面的代码。礼貌在这里

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());
}
}

在运行时,您将获得类型参数。因此,在您的类中,您将不得不定义一个Class对象来获取类,如上所述。然后使用Class.newInstance你得到一个新的对象。但是您将不得不手动处理类型转换等。

问题是:这一切值得吗?

根据我的说法,不,因为大多数情况可以通过在泛型类型中使用边界并与绑定类型接口来避免。所以你应该寻找替代解决方案

于 2013-07-24T18:20:32.790 回答
1

一个有启发性的练习是问自己,“如果没有泛型,我将如何做到这一点?” 这个问题的答案也是你问题的答案。

通过删除泛型并在正确的位置插入强制转换,可以将具有泛型的程序写入没有泛型的等效程序,而无需更改代码中的任何其他内容。这种转换称为“类型擦除”。这意味着如果没有泛型就无法编写某些东西,那么它也不能使用泛型编写。

如果没有泛型,您的代码如下所示:

public interface Formatter {
    String format(Object value);
}

private Map formatters;

public void addFormatter(Formatter formatter) {
    formatters.put(?, formatter);
}

所以,我问你,你会怎么做?

于 2013-07-24T21:11:48.787 回答
1

一般来说,这是不可能的。Formatter但是,在您的情况下,实现一个方法可能是合理的Class<T> getFormatterTargetClass(),然后您可以使用该方法而不是T.class在您的代码中。

于 2013-07-24T18:19:22.270 回答
1

由于类型擦除 T.class在运行时不可用,因此您必须传入一个单独的参数。通常,通用类型信息在运行时不可用(除非您使用无界通配符)。

于 2013-07-24T18:14:58.360 回答
1

这在 Java 语言中是不可能的。所有泛型类型都是在编译时确定的,因此您无法在执行时访问类值。因此,您还需要传递Class<T>参数才能访问它。

public Class MyGenericClassContainer<T>{

    public T instance;

    public Class<T> clazz;

    public MyGenericClassContainer(Class<T> clazz){
        intance = clazz.newInstance();
    }

}
于 2013-07-24T18:15:29.423 回答