1

Is this cast safe?

private <T> void foo(T value) {
    final Class<T> aClass = (Class<T>) value.getClass();
} 

Does a more elegant way exist to do this?

Is it possible to avoid unchecked cast warning?

Misha
  • 27,433
  • 6
  • 62
  • 78
gdomo
  • 1,650
  • 1
  • 9
  • 18
  • 3
    It is safe. do a check before casting `value!=null` – Khalid Shah Nov 15 '18 at 09:28
  • 1
    It is not actually safe. The `Class` object returned will not be of type `T` but rather the *erasure* of `T` (or possibly a subtype). If `T` is generic then the returned `Class` object will not reflect the generic parameters. This is a mild case of heap pollution. In most cases it's benign, but most likely the *correct* approach would be to use a `Type` object instead of a `Class` object. Whether that's actually useful or not depends on what you're trying to accomplish here. – Daniel Pryden Nov 23 '18 at 12:07

1 Answers1

2

You can suppress the compiler warning. See What is SuppressWarnings ("unchecked") in Java?

Compiler is warning you for a reason. value can contain an object of some subtype of T and there are important differences between Class<Parent> and Class<Child>. In your case, you can see that you are not doing anything unsafe, but the compiler just follows the rules.

Imagine if the method was slightly different and there was a way to get another value of type T:

<T> void foo(T a, T b) {
    final Class<T> aClass = (Class<T>) a.getClass();

    // What can go wrong?  casting T to T
    T c = aClass.cast(b);
}

// but what if the two parameters are of different classes at runtime
foo(5, 5.5);   // ClassCastException!

Or what if we allow Class<T> to escape as a return value:

<T> Class<T> foo(T val) {
    final Class<T> aClass = (Class<T>) val.getClass();
    return aClass;
}

// uhoh is declared as Class<Number> but contains Class<Integer> at runtime
Class<Number> uhoh = foo(5);

// Ok to cast Double to Number but not to Integer
Number num = uhoh.cast(5.5);  // ClassCastException!
Misha
  • 27,433
  • 6
  • 62
  • 78
  • 2
    This answer is correct, but it misses the additional issues that generic types throw into the mix. `foo(new ArrayList())` will return a value with the compile-time type of `Class>` even though that type is impossible at runtime: the actual class object at runtime would be `Class` for the corresponding raw type. – Daniel Pryden Nov 23 '18 at 12:13