· · ─ ·✶· ─ · ·

So recently I was writing a junit and ended up needing to use reflection to get access to a private class method to test it.

Method method = MergeSort.class.getDeclaredMethod(
        "merge",
        List.class,
        List.class
);
method.setAccessible(true);
List<Integer> mergedActual = (List<Integer>) method.invoke(mergeSort, left, right);

Intellij immediately gave me a warning - Unchecked cast: 'java.lang.Object' to 'java.util.List<java.lang.Integer>'

I understand that this is because invoke() gives back Object and and at compile time, the compiler has no idea if my method actually returns List<Integer> or not.

Now combine that with type erasure, which is something that happens at runtime.

At runtime, Java does not really know the generic parameter (Integer) anymore. A List<Integer> and List<String> are both just List at runtime. So the JVM can only verify:

Object -> List

but cannot verify:

Object -> List<Integer>

NOTE: The warning represents a concern at both, compile-time and runtime.


How to fix this?

  1. Suppress the warning if we know what we’re doing
@SuppressWarnings("unchecked")
List<Integer> mergedActual =
        (List<Integer>) method.invoke(mergeSort, left, right);
  1. We could cast to List<?>
List<?> mergedActual =
        (List<?>) method.invoke(mergeSort, left, right);

· · ─ ·✶· ─ · ·