如何创建已知类型的类文字:Class <list <string>&gt; </list <string>

时间:2010-01-06 10:45:50

标签: java generics jls

采取以下措施:

public Class<List<String>> getObjectType() {
    // what can I return here?
}

我可以从这个满足泛型和编译的方法返回什么类文字表达式? List.class将无法编译,List.<String>class也不会编译。

如果您想知道“为什么”,我正在编写Spring FactoryBean<List<String>>的实现,这需要我实现Class<List<String>> getObjectType()。但是,这是不是一个Spring问题。

编辑:SpringSource的权力听到了我的哀悼,因此Spring 3.0.1的返回类型getObjectType()已更改为Class<?> ,这可以很好地避免这个问题。

10 个答案:

答案 0 :(得分:42)

您可以随时投射到您需要的内容,例如

return (Class<List<String>>) new ArrayList<String>().getClass();

return (Class<List<String>>) Collections.<String>emptyList().getClass();

但我认为那不是你追求的。它有效,有警告,但它并不完全“漂亮”。

我刚发现了这个

  

为什么没有通配符参数化类型的类文字?

     

因为通配符参数化类型没有确切的运行时类型表示。

因此,施法可能是唯一的方法。

答案 1 :(得分:15)

你永远不应该使用构造Class<List<String>>。它是荒谬的,应该用Java产生警告(但不是)。类实例始终代表原始类型,因此您可以拥有Class<List>;而已。如果你想要某些东西来表示像List<String>这样的具体泛型类型,你需要一个像Guice一样的“超类型令牌”:

http://google-guice.googlecode.com/git/javadoc/com/google/inject/TypeLiteral.html

答案 2 :(得分:7)

Class<List<String>>的存在本质上是危险的。这就是原因:

// This statement generates a warning - for a reason...
Class<List<String>> unsafeListClass = (Class<List<String>>) (Class<?>) List.class;

List<Integer> integerList = new ArrayList<Integer>(); // Ok
integerList.add(42); // Ok

System.out.println(unsafeListClass.isInstance(integerList)); // Prints "true".
List<String> stringList =
   unsafeListClass.cast(integerList); // Succeeds, with no warning!
stringList.add("Hello, World!"); // Also succeeds with no warning

for (int x: integerList) {
    // Compiles without warning, but throws ClassCastException at runtime
    System.out.println(100-x);
}

答案 3 :(得分:6)

在springframework.org上找到了this link,提供了一些见解。

E.g。

List<String> myList = new ArrayList<String>();
return (Class<List<String>>)myList.getClass();

答案 4 :(得分:5)

您可以像这样实现该方法:

public Class<List<String>> getObjectType() {
    return (Class<List<String>>) ((Class)List.class);
}

答案 5 :(得分:2)

在SUN论坛上查看此讨论:

http://forums.sun.com/thread.jspa?threadID=5253007

引用的博客文章描述了使用“超类型令牌”的解决方法:

http://gafter.blogspot.com/2006/12/super-type-tokens.html

答案 6 :(得分:1)

我不确定这是否可行,因为任何类文字都将编译为Class.forName(...),因为这在运行时发生,所以没有遗留任何通用信息。

答案 7 :(得分:0)

我不确定,但我提出的以下问题可能与您有关...

java generics type parameters and operations on those types

答案 8 :(得分:0)

这个怎么样:

public class TestMain {
    public static void main(String[] args) throws Exception {
        Type type = TestMain.class.getMethod("dummy").getGenericReturnType();
        System.out.println("type = " + type);
    }

    public List<Integer> dummy() {return null;}
}

打印:

type = java.util.List<java.lang.Integer>

答案 9 :(得分:0)

以下方法存在问题:

> public Class<List<String>> getModelType() {
>   return (Class<List<String>>) new ArrayList<String>().getClass();
> }

e.g。如果你想测试一个对象是否说类型

org.eclipse.emf.common.util.BasicEList<String> 

的类型为

List<String> 

基于前面提到的getModelType()方法的结果,例如:

BasicEList<String> fromObject = ...;
if (getModelType().isAssignableFrom(fromObject.getClass())) {
    transferFromModelToUi(getModelType().cast(fromObject));
}

它将导致false,而它应该为true,因为两个对象都实现了接口List(因为getModelType()返回List类型的Class对象而不是ArrayList)。

这是一种对我有用的方法(有点麻烦,但在上面的例子中导致正确的结果,可以移动到静态初始化器):

public Class<List<String>> getModelType() {
    Class<?> arrayListClass = new ArrayList<String>().getClass();
    Class<?>[] interfaces = arrayListClass.getInterfaces();
    int index = 0;
    for (int i = 0; i < interfaces.length; i++) {
        if (interfaces[i].equals(List.class)) {
            index = i;
            break;
        }
    }
    return (Class<List<String>>) interfaces[index];
}