I have a class named Myclass, which is just a wrapper of a HashMap, I want to be able to store the possible key/value pair listed below:
KEY_A->MyClassAKEY_LIST_B->List<MyClassB>KEY_C->List<MyClassC>
Here is my code :
public class Main {
public static void main(String[] args) {
MYClass myClass = new MYClass();
myClass.set(MyEnum.KEY_A, new MyClassA());
myClass.set(MyEnum.KEY_LIST_B, new ArrayList<>(Arrays.asList(new MyClassB())));
myClass.set(MyEnum.KEY_C, new ArrayList<>(Arrays.asList(new MyClassC())));
MyClassA a = (MyClassA) myClass.get(MyEnum.KEY_A);
List<MyClassB> listB = (List<MyClassB>) myClass.get(MyEnum.KEY_LIST_B);//Unchecked cast
List<MyClassC> listC = (List<MyClassC>) myClass.get(MyEnum.KEY_C);//Unchecked cast
}
public static class MYClass {
private final HashMap<MyEnum, Object> map;
public MYClass() { map = new HashMap<>(); }
public Object get(MyEnum key) { return map.get(key); }
public void set(MyEnum key, Object value) { map.put(key, value); }
}
public static class MyClassA {}
public static class MyClassB {}
public static class MyClassC {}
public enum MyEnum {KEY_A, KEY_LIST_B, KEY_C}
}
How can I design (signature of these methods) the
get()andset()methods ofMyClassto be able to store the key/value pair listed earlier and avoid theUnchecked cast?Why this line does not have
Unchecked castwarning even if the cast is not safe ?MyClassA a = (MyClassA) myClass.get(MyEnum.KEY_A);
A typical solution would be to use a generic "key class" that carries information regarding the value type. Instances of the key would have a reference to the value type's
Class. Note your enum is close to this solution, but unfortunately you can't have a generic enum where each constant has different type arguments.Here's an example:
I personally would be okay with this implementation, as the (suppressed) warnings only occur inside
Container. Code which uses theContainerclass won't encounter unchecked cast or raw type warnings.The reason for the
@SuppressWarningsannotations is because aClasscannot legitimately represent a parameterized type. In other words, you can have aClass<List>but not aClass<List<Foo>>1. However, if you want to avoid even suppressing these warnings, then the only approach I can think of is to create wrapper classes for your generic value types. Such as:And then have a
Key<MyClassBList>.As for why:
Does not cause an "unchecked cast" warning to be omitted, that's because there's no generics involved. If the above cast is not possible at run-time, then a
ClassCastExceptionwould be thrown. But when generics are involved, then the cast might succeed even if you "change" the type arguments. For instance:And that mess of a situation is why they warn you about "unchecked casts". The
Containerexample above should not be able to result in such problems due to howputandgetare defined, unless you deliberately and explicitly try to break things (e.g., by using raw types, casting "hacks", etc.).1. You technically can have a reference to a
Class<List<Foo>>, by doing something similar to what I did withKeyabove, but it would not actually represent aList<Foo>.