Generics_Part 2

1. Generic type casting

    Person<Object> person1 = null;
    Person<String> person2 = null;
    Person<? extends Object> person3 = null;

    person1 = (Person<Object>)person2; //error!
    person2 = (Person<String>)person1; //error!
    person3 = new Person<String>();//OK!
  • This is quite expected. The substituted type should be matched, even if it is an object type.
public final class Optional<T> {
    private static final Optional<?> EMPTY = new Optional<>();
    private final T value;
    private Optional() {
        this.value = null;
    }
    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }
  • Above is a fraction of actual Java Optional class.
  • <?> is identical to <? extends Object>
  • Since a new method should always have a concrete type, new Optional<>() is actually new Optional()
  • Let us think about why the type of EMPTY was set Optional<?> and not Optioanl<Object>
    Optional<?> opt1 = new Optional<Object>();
    Optional<Object> opt2 = new Optional<Object>();

    Optional<String> stropt1 = (Optional<String>)opt1; //OK
    Optional<String> stropt1 = (Optional<String>)opt2; //Error!
  • To conclude, casting Optional<Object> to Optional is impossible. **Optional\ -> Optional\**
  • But, Optional<Object> -> Optional<?> -> Optional<T> is possible

How Generic type is actually compiled

    1. Compiler checks source file with Generic type, and casts wherever is necessary
    1. Compiler removes the generic type. Hence, the compiled class file (*.class) does NOT have any information about the generic type.