Generated Java Data Transfer Options

Hope someone can help me with this misunderstanding.

I made this method:

public static <T> void myMethod(Map<Class<T>, MyInterface<T>> map) { } 

The T parameter is used to ensure that the class used as the key is the same as the class used as the parameter in MyInterface.

Now I want to pass a map, which, of course, has different classes as keys and corresponding implementations of MyInterface.

But this will not work, receiving syntax errors due to type parameters. Here is the code, I hope, explain it myself.

  import java.util.HashMap; import java.util.Map; public class Test { public static void main(String[] args) { Map<Class<?>, MyInterface<?>> map = new HashMap<Class<?>, MyInterface<?>>(); // Map<Class<Object>, MyInterface<Object>> map = new HashMap<Class<Object>, MyInterface<Object>>(); map.put(Object.class, new MyObjectImpl()); //if I use Map<Class<Object>, MyInterface<Object>> I get a compiler error here //because map<String> is not map<Object> basically map.put(String.class, new MyStringImpl()); //this would be possible using <?>, which is exactly what I don't want // map.put(String.class, new MyIntegerImpl()); //<?> generates anyways a compiler error myMethod(map); } //use T to make sure the class used as key is the same as the class of the parameter "object" in doSomething public static <T> void myMethod(Map<Class<T>, MyInterface<T>> map) { } interface MyInterface<T> { void doSomething(T object); } static class MyObjectImpl implements MyInterface<Object> { @Override public void doSomething(Object object) { System.out.println("MyObjectImpl doSomething"); } } static class MyStringImpl implements MyInterface<String> { @Override public void doSomething(String object) { System.out.println("MyStringImpl doSomething"); } } static class MyIntegerImpl implements MyInterface<Integer> { @Override public void doSomething(Integer object) { System.out.println("MyIntegerImpl doSomething"); } } } 
+7
source share
4 answers

You cannot do this because in Map put() there are no restrictions between key and value . If you want to make sure that your map is filled out properly (i.e. create such a restriction), hide the map behind some API that will check the correctness, for example:

 public <T> void registerInterface(Class<T> clazz, MyInterface<T> intf) { map.put(clazz, intf); } 

Then just call registerInterface instead of manually populating the map.

+8
source

As far as I know, you cannot declare a map as you describe in Java. All you can do is perform type checking and / or add constraints.

Guava offers something that fits your issue with ClassToInstanceMap . So one way to do this would be to use MapConstraints.constrainedMap (like the example below)

 import java.text.ParseException; import java.util.HashMap; import java.util.Map; import com.google.common.collect.MapConstraint; import com.google.common.collect.MapConstraints; public class Main { interface MyInterface<T> { void doSomething(T object); Class<T> getType(); } static class MyObjectImpl implements MyInterface<Object> { @Override public void doSomething(Object object) { System.out.println("MyObjectImpl doSomething"); } @Override public Class<Object> getType() { return Object.class; } } static class MyStringImpl implements MyInterface<String> { @Override public void doSomething(String object) { System.out.println("MyStringImpl doSomething"); } @Override public Class<String> getType() { return String.class; } } static class MyIntegerImpl implements MyInterface<Integer> { @Override public void doSomething(Integer object) { System.out.println("MyIntegerImpl doSomething"); } @Override public Class<Integer> getType() { return Integer.class; } } public static void main(String[] args) throws ParseException { Map<Class<?>, MyInterface<?>> map = MapConstraints.constrainedMap(new HashMap<Class<?>, Main.MyInterface<?>>(), new MapConstraint<Class<?>, MyInterface<?>>() { @Override public void checkKeyValue(Class<?> key, MyInterface<?> value) { if (value == null) { throw new NullPointerException("value cannot be null"); } if (value.getType() != key) { throw new IllegalArgumentException("Value is not of the correct type"); } } }); map.put(Integer.class, new MyIntegerImpl()); map.put(String.class, new MyStringImpl()); map.put(Object.class, new MyObjectImpl()); map.put(Float.class, new MyIntegerImpl()); //<-- Here you will get an exception } } 
+3
source

I do not think that's possible:

Class<T> only takes T.class as a value. Class<Object> does not accept String.class , although Object is a superclass of String.

For this reason, any card with Class<T> as a key can have only one element with T.class as the key value, regardless of the value of T

The compiler will only ever accept a card with a specific parameter value T as a parameter. You cannot write Map<Class<?>, MyInterface<?>> because everyone? it is assumed to be different: it does not match Map<Class<T>, MyInterface<T>> , which requires that the value of T have the same value.

However, myMethod will only accept one-time cards that do not seem useful.

0
source

Change your method signature to

 public static <T> void myMethod(Map<Class<? extends T>, MyInterface<? extends T>> map) { } 

now your declaration and challenge should work.

 Map<Class<?>, MyInterface<?>> map = new HashMap<Class<?>, MyInterface<?>>(); map.put(Integer.class, new MyIntegerImpl()); map.put(String.class, new MyStringImpl()); map.put(Object.class, new MyObjectImpl()); myMethod(map); 
0
source

All Articles