A common method triggers a type of security error - why?

While playing with solutions for this issue, I came up with the following code, which has some warnings about the compiler. One warning:

Type safety: The expression of type Test.EntityCollection needs unchecked conversion to conform to Test.EntityCollection<Test.Entity>

I do not quite understand why this warning appears. Passing in type Class<M> and declaring that the method returns EntityCollection<M> , why am I not doing enough to convince the compiler (Java 7) that the correct type is being returned?

 static class Entity { } static class EntityCollection<E extends Entity> { private EntityCollection(HashMap<?, E> map) { } public static <T extends HashMap<?, M>, M extends Entity> EntityCollection<M> getInstance( Class<T> mapType, Class<M> entityType) throws ReflectiveOperationException { T map = mapType.getConstructor().newInstance(); return new EntityCollection<M>(map); } } public static void main(String[] args) throws Exception { // both compiler warnings are on the line below: EntityCollection<Entity> collection = EntityCollection.getInstance( LinkedHashMap.class, Entity.class); } 

Bonus points if someone can improve the code to completely avoid warnings. I looked at him for a while and did not think about reducing the warnings.

+7
java generics
source share
2 answers

The problem is that getInstance is a generic method, but you are not passing general type parameters to it. You can get around this by passing them as follows:

  public static void main(String[] args) throws Exception { EntityCollection<Entity> collection = EntityCollection.<LinkedHashMap, Entity>getInstance( LinkedHashMap.class, Entity.class); } 

You still have to handle the rawtypes warning because LinkedHashMap is a generic type. This is problematic in your case, since there is a wildcard in the key type.

Here you encounter several problems:

You cannot pass parameterized class objects like this: LinkedHashMap<Object, Entity>.class , so that you are pretty much stuck in the rawtypes warning.

+3
source share

The problem is T. You add a constraint to your method, saying that T should extend HashMap<?, M> . However, the way you later reference T is similar to a generic parameter of type Class (Class<T>) . LinkedHashMap.class is of type Class<LinkedHashMap> not Class<LinkedHashmap<?, Entity>> (this is what you need)

A class object always refers to a non-parameterized type, and that makes sense. Since a common binding exists at compile time, and you are going to use this class to dynamically reflect the state and behavior of an instance at runtime. In short, you can use Class<HashMap> to create a new instance, not limited to any type.

So, I think what you need to do for your code is to change this restriction the way it looks:

 public static <T extends HashMap, M extends Entity> EntityCollection<M> getInstance( Class<T> mapType, Class<M> entityType) throws ReflectiveOperationException { T map = mapType.getConstructor().newInstance(); return new EntityCollection<M>(map); } 
+1
source share