Hope somebody can help me out of this confussion.
I made this method:
public static <T> void myMethod(Map<Class<T>, MyInterface<T>> map) {
}
Used paramter T in order to make sure that the class used as key is the same as the class used as parameter in MyInterface.
Now I want to pass a map which different classes as keys, of course, and corresponding implementations of MyInterface.
But it doesn't work, getting syntax errors because of type parameters. Here is the code, I hope is self explanatory.
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");
}
}
}
You can't do that, because there is no constraint defined in Map
's put()
method between the key
and the value
. If you want to assure that your map is populated properly (i.e. create such constraint), 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 the registerInterface
instead of manually populating the map.
As far as I know, you cannot declare a Map like you describe in Java. All you can do is performing type checking and/or add constraints.
Guava offers something that approaches your problem 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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With