2

I wonder if it is possible to write a method that will handle casting of undefined types like:

Precondition:

Map<String, Object> map = new HashMap<>();
List<String> l = List.of("value");
map.put("key", l);

Method call:

List<String> strings = convert("key", List.class, String.class);

convert method itself:

public <V, C extends Collection<V>> C<V> getCollection(String key, Class<C> collType, Class<V> objectType) {
    return (C<V>) map.get(key);
}

But statement C< V > doesn't compile and gives me an error: Type 'C' doesn't have type parameters.

Any ideas?

michid
  • 10,536
  • 3
  • 32
  • 59
Serhii Kachan
  • 345
  • 4
  • 13
  • 1
    Not possible. Java does not support higher-kinded types. – Sweeper Mar 17 '22 at 14:18
  • 1
    Doesn't `(C)` work? – Andy Turner Mar 17 '22 at 14:30
  • Java generics are a compile time "syntactic sugar" that allows safe checking of types. Generic are literally erased at runtime -- all those generics are replaced with `Object` and the runtime doesn't know about the types you used (I think the compiler will insert a `(cast)` when needed for you). If you need runtime type safety, look at the heterogeneous container pattern. https://codereview.stackexchange.com/questions/55737/typesafe-heterogeneous-container – markspace Mar 17 '22 at 14:36

1 Answers1

1

Java uses target typing in type inference which means the expected type on the right-hand side of an assignment can be leveraged for this purpose.

Map<String, Object> map = Map.of("strings", List.of("value"));

However, to take advantage of it an unchecked cast is needed:

<T> T convert(Map<String, Object> map, String key) {
    return (T) map.get(key);   // Warning: unchecked cast
}

You could then get the typed entry out of the map:

List<String> strings = convert(map, "strings");

However, because of type erasure of Java generics, the type parameter is not checked at runtime. So while this will throw a ClassCastException:

Set<String> setOfString = convert(map, "strings");

This will execute without any complaint, and you won't get a ClassCastException until you try to extract the values from the list:

List<Integer> numbers = convert(map, "strings");
David Conrad
  • 15,432
  • 2
  • 42
  • 54