How to create a class literal of a known type: Class<List<String>>
Solution 1
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.
Solution 2
You should never use the construct Class<List<String>>
. It is nonsensical, and should produce a warning in Java (but doesn't). Class instances always represent raw types, so you can have 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:
http://google-guice.googlecode.com/git/javadoc/com/google/inject/TypeLiteral.html
Solution 3
You can implement that method like this:
public Class<List<String>> getObjectType() {
return (Class<List<String>>) ((Class)List.class);
}
Solution 4
The existence of a Class<List<String>>
is inherently dangerous. 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);
}
Solution 5
Found this link on springframework.org which gives some insight.
E.g.
List<String> myList = new ArrayList<String>();
return (Class<List<String>>)myList.getClass();
skaffman
Updated on January 16, 2020Comments
-
skaffman over 4 years
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 willList.<String>class
.If you're wondering "why", I'm writing an implementation of Spring's
FactoryBean<List<String>>
, which requires me to implementClass<List<String>> getObjectType()
. However, this is not a Spring question.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 toClass<?>
, which neatly avoids the problem. -
JRL over 14 years@Bozho: the springframework link has a different method signature
java.lang.Class<? extends T> getObjectType()
. I've updated my answer to reflect the signature of the OP's question. -
skaffman over 14 yearsWhere did you find that quote?
-
skaffman about 14 yearsI agree that it's not a good idea, but Java permits it, and if you're trying to implement an interface, you may have no choice in the matter, so we still need a way of doing it (semi-)elegantly.
-
user over 9 yearsYour first example did not work for me (SE 1.6), only the second example did. Instantiating the ArrayList to a variable and returning myVar.getClass() works though. found : java.lang.Class<capture#972 of ? extends java.util.ArrayList> required: java.lang.Class<java.util.List<com.foo.Bar>>
-
Peter Kriens over 8 yearsThat is a strange example. Since generics are not reified in runtime runtime casting bypasses the generic type system in many cases. Generics are mostly a compile time construct that allows you to further constrain a type from a class type. It would be useful if you could keep the generic signature because, as long as you don't cast, would make a lot of code more readable AND typesafe.
-
Martin Forte over 7 yearsI like this way because you don't need create a new instances.
-
TXN over 4 yearsThe outer cast is unnecessary. You can write it like this instead:
return (Class)List.class;
, which I find easier to read.