Student01
Student01

Reputation: 109

Java generics unchecked warnings for extended classes

I have the following code:

public class Foo {

    interface Coo<T> {
        public T cool();
    }

    abstract class Bar<T extends Bar<T>> implements Coo<T>  {

        @SuppressWarnings("unchecked")
        T doSomething() {
            return (T) this;
        }

        @SuppressWarnings("unchecked")
        @Override
        public T cool() {
            return (T) this;
        }

    }

    class FooBar extends Bar<FooBar> {
        @Override
        public FooBar cool() {
            return super.cool();
        }

    }
}

Why is the cast to (this) object type unsafe? When Bar implements Coo, isn't the generic saying that returned cool must be of type T, which extends Bar or its subclasses?

Upvotes: 1

Views: 313

Answers (2)

newacct
newacct

Reputation: 122449

T extends Bar<T>, but Bar<T> (the type of this) does not extend T.

Imagine

class A extends Bar<A> { ... }
class B extends Bar<A> { ... }

Then the method becomes inherited as:

class B {
    A doSomething() {
        return (A) this;
    }
}

which is obviously not right.

It is not possible to do what you want with generics. It is a big misconception among people. They think that recursive bounds will allow you to do self-types. But recursive bounds are ALMOST NEVER useful in Java. 99% of the places where you see people write interface Bar<T extends Bar<T>>, it would be just as good to write it as interface Bar<T>.

Upvotes: 1

reprogrammer
reprogrammer

Reputation: 14718

Because this in Bar has type Bar<T extends Bar<T>> but not T, the compiler generates warnings for Bar#doSomething. The following won't generate any warnings:

abstract class Bar<T extends Bar<T>> {

    Bar<T> doSomething() {
        return this;
    }

}

The body of Bar#cool expects this to be a subtype of T which is not the case. In Bar#cool, this has type Bar<T extends Bar<T>> and is a subtype of Coo<T> but not T.

Upvotes: 3

Related Questions