Search code examples
javagenericstype-inference

Return type of a method is affected by type parameter of a class although the type parameter is not used anywhere. Why?


In the following source code, why is return type of method WParam.unwrap(…) affected by type parameter <X> even though it is not used anywhere?

public class TestClass {
    void test() {
        final Long val1 = new Simple().unwrap(new Wrapper<>(5L));    // OK
        final Long val2 = new WParam().unwrap(new Wrapper<>(5L));    // ERROR: Object cannot be converted to Long
        final Long val3 = new WParam<>().unwrap(new Wrapper<>(5L));  // OK
        final Long val4 = new WParam<Byte>().unwrap(new Wrapper<>(5L)); // OK
    }
}


record Wrapper<O>(O obj) {}

class Simple {
    public <T> T unwrap(Wrapper<T> wrapper) {
        return wrapper.obj();
    }
}

class WParam<X> {
    public <T> T unwrap(Wrapper<T> wrapper) {
        return wrapper.obj();
    }
}

Solution

  • So why does final Long val3 = new WParam<>().unwrap(new Wrapper<>(5L)) work, but final Long val2 = new WParam().unwrap(new Wrapper<>(5L)); doesn't?

    It boils down to the fact that new WParam() is a raw type and therefore loses all type information. All generic types not used in a static context are erased, even those that don't belong to the type parameter in your class definition.

    That's why the return type of unwrap is actually Object and cannot be cast to Long, just as the exception tells you.

    For more information, have a look at What is a raw type and why shouldn't we use it?