In Java, how can I avoid raw types when calling getClass on an instance of a generic type?

Suppose I have this in Java:

List<String> list = new ArrayList<String>(); list.getClass(); 

Type of last expression Class<? extends List> Class<? extends List> . I understand why, due to erasure, this cannot be Class<? extends List<String>> Class<? extends List<String>> . But why can't it be Class<? extends List<?>> Class<? extends List<?>> ?

Is there a way to avoid the warning of unchecked throw warnings and warnings of type raw if I want to assign the result of this expression to a variable that somehow preserves that this class is actually a kind of List ?

 Class<? extends List> listClass = list.getClass(); // raw type warning Class<? extends List<?>> listClass = (Class<? extends List<?>>) list.getClass(); // unchecked cast warning 
+8
java generics bounded-wildcard reflection language-design
source share
2 answers

When generics were first introduced, getClass returned Class<? extends X> Class<? extends X> Class<? extends X> Class<? extends X> , where X is the static type of expression on which it was called. This led to unreasonable compilation problems, as reported in this Oracle error . Here is an example error report:

The following code fragment does not compile

 void f(List<Integer> li, List<String> ls) { if (li.getClass() == ls.getClass()) ; } 

because the intersection of Class<List<Integer>> and Class<List<String>> empty.

This problem was resolved by expanding the return type of getClass as it is now. From the documentation :

The actual type of result is Class<? extends |X|> Class<? extends |X|> Class<? extends |X|> Class<? extends |X|> where |X| erases the static type of the expression on which getClass is invoked.

This resolved the above question, but therefore led to what your question indicates. Soon after, another error was reported stating the following:

I think the input rule getClass() can be changed to Class<? extends wildcard(T)> Class<? extends wildcard(T)> Class<? extends wildcard(T)> Class<? extends wildcard(T)>

The wildcard operation is defined as follows: if the parameter T parameterized, wildcard(T)=erasure(T)<?> Else, wildcard(T)=T

JUSTIFICATION:

  1. This rule introduces a raw type. The raw type should only be used to interact with legacy code.

  2. The new rule introduces a wildcard. The relationship between a parameterized type and a wildcard is based on subtyping rules. The relationship between a parameterized type and a wildcard is based on the conversion of the original type.

This error did not work and remains open to this day, with the following counterarguments:

The sentence means getClass() will return Class<? extends ArrayList<?>> Class<? extends ArrayList<?>> Class<? extends ArrayList<?>> Class<? extends ArrayList<?>> an object that is incompatible with another Class<? extends ArrayList<?>> Class<? extends ArrayList<?>> Class<? extends ArrayList<?>> Class<? extends ArrayList<?>> Class<? extends ArrayList<?>> objects Class<? extends ArrayList<?>> . This is compatible with existing code, for example:

 List<String> l = ...; Class<? extends List> c = l.getClass(); 

because the new type is RHS, Class<? extends List<?>> Class<? extends List<?>> Class<? extends List<?>> Class<? extends List<?>> , is a subtype of Class<? extends List> Class<? extends List> Class<? extends List> Class<? extends List> .

The disadvantage of enriching a class type argument is that it violates the idiomatic use of Class.cast . Today you can write:

 List<Integer> x = ...; Class<? extends List> cl = x.getClass(); List<Integer> y = cl.cast(null); 

and get a warning in cast() due to an unchecked conversion from List to List<Integer> . But with the sentence, the similar code does not compile:

 List<Integer> x = ...; Class<? extends List<?>> cl = x.getClass(); List<Integer> y = cl.cast(null); 

because the List<?> returned by cast() cannot be converted to List<Integer> . The only way to avoid the error is to cl.cast(..) before List and transfer the warning about unverified conversion to List<Integer> . This is actually what getClass() does.

In general, the proposal seems to be a good idea, but it has moderate complexity and a rather small gain.

(shortened and corrected with some typos)

+5
source share

Being that List is an interface, I'm not sure if you can find out that the List interface is implemented for ArrayList . A link was found here that might help.

I talked a bit with this and found that ...

  Class<?> d = list.getClass(); d.equals(ArrayList.class); 

but I'm not sure if this is what you are looking for ...

Good luck

-3
source share

All Articles