2010-02-09 42 views
17

我试图从接口配置文件中读取一个接口到它的实现,这样我就可以将它提供给我的IoC容器。这里的大概就是我想要做的事:尽管Java的类型擦除获得T.class

public class PropertyImplementationBinder<T> { 
    // ... 
    public Class getInterfaceClass() { 
     return T.class; // OR Class<T>, note T is not newable 
    } 
    public Class getImplementationClass() { 
     return /* read config file to get implementation class */; 
    } 
} 

是它在某种程度上可能得到T.class

+2

[this one](http://stackoverflow.com/a/1005283/1416458)看起来更优雅 – jpfreire 2013-01-28 03:19:13

回答

30

您需要显式地将该类传递给构造函数(并自行存储)。

private final Class<T> clazz; 

PropertyImplementationBinder(Class<T> clazz){ 
    this.clazz = clazz; 
} 

public Class<T> getInterfaceClass() { 
    return clazz; 
} 
+0

我认为这对我来说应该是显而易见的......但事实并非如此。谢谢! – 2010-02-09 05:12:27

+12

为什么语言无法为我们做到这一点? – Pacerier 2012-03-06 11:45:30

+0

如果它是在版本1中为它设计的,那么语言本可以为我们完成它。它是一个向后兼容的东西。通过将这些内容插入到Java 5中而没有破坏旧的代码,只有这么多才能做到。 – Thilo 2012-03-07 00:11:19

-1

不,这是不可能的。

Java的类型擦除的唯一例外是通过反射你可以通过类的字段上的反射找出参数化类型。

+0

不,您还可以从Class.getGeneric *()和Method.getGeneric *()中查找参数化类型信息。 – Andy 2013-10-25 15:45:14

+0

可以看到上面的答案。 – okigan 2014-04-10 17:17:11

8

您可以获取类的泛型超类的实际类型参数。这blog post探讨了这种可能性,包括使用普通的匿名内部类的一个很好的小技巧。要直接引用:

事实证明,尽管JVM不会跟踪泛型类实例的实际类型参数,它不跟踪实际的类型参数子泛型类的。换句话说,尽管在运行时new ArrayList<String>()实际上只是一个new ArrayList(),但如果一个类扩展了ArrayList<String>,那么JVM知道StringList的类型参数的实际类型参数。

+1

但是开发人员知道,因为类有一个静态T.它不会在运行时更改。 – GuiSim 2014-06-24 14:26:32

5

与普遍接受的相反,很少知道类型擦除可以避免,这意味着被调用者确实有能力知道在调用过程中使用了哪些通用参数。

请看看: Using TypeTokens to retrieve generic parameters

文章还对我们的用户与技术经验会谈。简而言之,我们最终回落至...

常规和广泛使用的技术:“在构造函数传递类类型”

+1

好吧,这是令人毛骨悚然,但令人惊叹(让这是最后的魅力评论)。我真的相信这应该是正确的答案,并提出“你也可以在构造函数中传递类” – durilka 2012-01-12 22:26:23

+0

@durilka:非常感谢您的反馈 – 2012-07-07 11:46:23

+0

链接看起来被打破了......我知道Google的GSON库使用这种方法,并且我想读一篇关于它是如何工作的文章 – 2012-12-22 05:54:00

1

顺便说一句。来自@Richard Gomes的文章中的示例静态方法getType有两个错误。它应该是这样的:

static public Class<?> getType(final Class<?> klass, final int pos) { 
    // obtain anonymous, if any, class for 'this' instance 
    final Type superclass = klass.getGenericSuperclass(); 

    // test if an anonymous class was employed during the call 
    if (!(superclass instanceof ParameterizedType)) { 
      throw new RuntimeException("This instance should belong to an anonymous class"); 
    } 

    // obtain RTTI of all generic parameters 
    final Type[] types = ((ParameterizedType) superclass).getActualTypeArguments(); 

    // test if enough generic parameters were passed 
    if (pos >= types.length) { 
      throw new RuntimeException(String.format("Could not find generic parameter #%d because only %d parameters were passed", pos, types.length)); 
    } 

    if (!(types[pos] instanceof Class<?>)) { 
      throw new RuntimeException("Generic type is not a class but declaration definition(all you get is \"[T]\") " + types[pos]); 
    } 
    // return the type descriptor of the requested generic parameter 
    return (Class<?>) types[pos]; 
} 

遗憾的是它仍然不是灵丹妙药,因为它,如果你在代码中明确

getType(new SomeObject<String>(){}.class, 0) // you get String.class 

有工作,但如果你把这个东西就像

getType(new SomeObject<T>(){}.class, 0) // you get T as TypeVariable<D> and not actuall class of it 

Just name T.

+1

在第二个示例中,如果TypeVariable.getGenericDeclaration()可能仍然可以找到T的实际类型参数, '是一个类。在任何情况下,都需要花费大量工作来充实实际的类型参数(特别是如果它们是由超类定义的,有多个类型参数等,但我已经编写了代码来完成它。 – Andy 2013-10-25 15:50:52