简体   繁体   English

如何创建已知类型的类文字:类<List<String> &gt;

[英]How to create a class literal of a known type: Class<List<String>>

Take the following:采取以下措施:

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

What class literal expression can I return from this method which will satisfy the generics and compile?我可以从这个方法返回什么类文字表达式来满足泛型并编译? List.class won't compile, and neither will List.<String>class . List.class不会编译, List.<String>class也不会。

If you're wondering "why", I'm writing an implementation of Spring's FactoryBean<List<String>> , which requires me to implement Class<List<String>> getObjectType() .如果您想知道“为什么”,我正在编写 Spring 的FactoryBean<List<String>> ,它要求我实现Class<List<String>> getObjectType() However, this is not a Spring question.但是,这不是Spring 问题。

edit: My plaintive cries have been heard by the powers that be at SpringSource, and so Spring 3.0.1 will have the return type of getObjectType() changed to Class<?> , which neatly avoids the problem.编辑: SpringSource 的权力已经听到了我的悲痛呼喊,因此 Spring 3.0.1 将getObjectType()的返回类型更改为Class<?> ,这巧妙地避免了这个问题。

You can always cast to what you need, like this你总是可以投射到你需要的,像这样

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

or或者

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

But I assume that's not what you are after.但我认为这不是你所追求的。 Well it works, with a warning, but it isn't exactly "beautiful".好吧,它可以工作,但有警告,但它并不完全“美丽”。

I just found this我刚找到这个

Why is there no class literal for wildcard parameterized types?为什么通配符参数化类型没有类文字?

Because a wildcard parameterized type has no exact runtime type representation.因为通配符参数化类型没有精确的运行时类型表示。

So casting might be the only way to go.因此,铸造可能是唯一的出路。

You should never use the construct Class<List<String>> .你永远不应该使用构造Class<List<String>> It is nonsensical, and should produce a warning in Java (but doesn't).这是荒谬的,应该在 Java 中产生警告(但不会)。 Class instances always represent raw types, so you can have Class<List> ;类实例总是代表原始类型,所以你可以有Class<List> that's it.就是这样。 If you want something to represent a reified generic type like List<String> , you need a "super type token" like Guice uses:如果你想要一些东西来表示像List<String>这样具体的泛型类型,你需要一个像 Guice 使用的“超类型标记”:

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

You can implement that method like this:您可以像这样实现该方法:

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

The existence of a Class<List<String>> is inherently dangerous. Class<List<String>>存在本质上是危险的。 here's why:原因如下:

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

Found this link on springframework.org which gives some insight.在 springframework.org 上找到了这个链接,它提供了一些见解。

Eg例如

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

Check out this discussion on the SUN forums:在 SUN 论坛上查看此讨论:

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

And the referenced blog post that describes a work around by using "super type tokens":引用的博客文章描述了使用“超级类型令牌”的解决方法:

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

我不确定这是否可能,因为任何类文字都将被编译为Class.forName(...)并且由于这是在运行时发生的,因此没有留下任何通用信息。

What about this:那这个呢:

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

This prints:这打印:

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

I am not sure but the following question I asked might be of relevance to you... 我不确定,但是我问的以下问题可能与您有关...

java generics type parameters and operations on those types Java泛型类型参数和对这些类型的操作

The following approach is problematic:以下方法有问题:

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

eg if you want to test whether an object say of type例如,如果你想测试一个对象是否说类型

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

is of type是类型

List<String> 

based on the result of the aforementioned getModelType() approach, for example:基于上述 getModelType() 方法的结果,例如:

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

it will result in false whereas it should be true because both objects implement the interface List (since getModelType() returns a Class object of type List and not ArrayList).它将导致 false 而它应该是 true 因为这两个对象都实现了接口 List (因为 getModelType() 返回类型为 List 而不是 ArrayList 的 Class 对象)。

Here is an approach that worked for me (a bit cumbersome but leads to correct results in the example above, could be moved to a static initializer):这是一种对我有用的方法(有点麻烦但在上面的示例中会导致正确的结果,可以移至静态初始化程序):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM