"class A <T extends SomeClass<T>>" works differently from class B <T extends SomeInterface<T>> ? (Yes)

RFS :

While the definition involving interface Comparable

class B <T extends Comparable<T>>

is well known and instantiable, the same usage does not work in the same manner when extending a class instead of an interface. Here's an example

class G <T extends Box<T>> {
    T val;
    G(T val) {
        this.val = val;
    }
}

The above class compiles, but I am unable to find a way to instantiate G. It seems to require an infinite nesting of Box.

G<Box<Box<..>>>

Here is my definition of class Box

class Box <T> {
    T val;
    Box(T val) {
        this.val = val;
    }
}

To aid in discussion, here are a few similar examples. I tested all of my code.

The meaning of the following class is clear to me

class D <T extends Box<String>> {
    T val;
    D(T val) {
        this.val = val;
    }
}

we can instantiate using

    D<Box<String>> d = new D<>( new Box<String> ("hello") );

We can generalize this so that the Box can contain anything

class F <S, T extends Box<S>> {
    T val;
    F(T val) {
        this.val = val;
    }
}

we can instantiate using

    F<String,Box<String>> f = new F<>( new Box<String> ("hello") );

Back to the original question, what does the following mean and how/can it be instantiated?

class G <T extends Box<T>> {
    T val;
    G(T val) {
        this.val = val;
    }
}

This class G was my first attempt to generalize the class D above so that Box can hold any type, not just String. I later came up with class F as the solution to my problem, but I am left wondering what does G mean and why is it different from when T extends SomeInterface<T>.

Ruslan :

If Box class doesn't have constructor with T, then you can create a class that extends Box. For example:

class NewBox extends Box<NewBox> {
    ...
}

Then you can instantiate G like:

G<NewBox> g = new G<>(new NewBox());

But in your case Box has constructor Box(T val){...}, then NewBox required constructor matching super like:

class NewBox extends Box<NewBox> {
    NewBox(NewBox val) {
        super(val);
    }
}

To instantiate this you should end up with null, otherwise it will lead to infinite nesting :

G<NewBox> g = new G<>(new NewBox(new NewBox(new NewBox(null))));

Update: to answer your original question: G <T extends Box<T>> means that T must be type of Box or any descendant of Box. As you correctly mentioned it will lead to infinite nesting. But you still can instantiate this without creating extra class (as above with NewBox) using Wildcard and null as a parameter to the constructor of class G like:

G<?> tg = new G<>(null);

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=143247&siteId=1