Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
311 views
in Technique[技术] by (71.8m points)

java - When is there need for Some<E extends Some<E>> instead of Some<E extends Some>?

NOTE: This question is not Enum-related, so it's not duplicate. Enum's are forced to compare only-with-itself because compiler generation of type parameter, not because java recursive type parameter.

I'm trying to find an advantage for declaring a class as:

public class Some<E extends Some<E>>

versus declaring it as:

public class Some<E extends Some>

I have tried providing methods returning E and methods returning Some<E>, different cross-calls in complicated class hierarchy and every time I've tried to remove additional <E> - no new errors/warnings came up.

Can you show me a method that proves the advantage of this additional <E>? I assume that there exists one because of JDK declarations:<E extends Comparable<? super E>>

Responses to other questions on SO gives for example:

With the additional construct, you know that any class that extends Enum is comparable only against itself

But, I can easily break this theory:

public static class Animal<E extends Animal<E>> {
    public boolean compare(E other) {...}
}

public class Cat extends Animal<Cat> { }
public class Dog extends Animal<Cat> { } // Note "Cat" !!!

Despite the generic recursion, i can still compare Dog with Cat:

Dog dog = new Dog();
dog.compare(new Cat());

Transalting theory:

you know that any class that extends Animal is comparable only against itself

this is false - I comapred class Dog which extends Animal with Cat, not itself.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There are very few situations in which a bound like class Some<E extends Some<E>> is necessary. Most of the time people write this, the bound is not actually utilized in the code, and class Some<E> would work just as well.

However, there are some particular situations in which the bound in class Some<E extends Some<E>> is actually used. For example:

abstract class Some<E extends Some<E>> {
    abstract E foo();
    Some<E> bar() {
        return foo();
    }
}

As to your question -- what about class Some<E extends Some>? Well, first most glaring issue is that you're using a raw type. Raw types should never be used in new code. But you are not convinced.

The raw type with the above class (class Some<E extends Some>) does compile with a warning (which you can ignore to your own peril). However, the raw type means it's possible to do unsafe things with it.

It takes some effort to come up with an example to demonstrate that it's unsafe. Here is one:

abstract class Some<E extends Some> {
    abstract E foo();
    Some<E> bar() {
        return foo();
    }
}

class SomeFoo extends Some<SomeFoo> {
    SomeFoo foo() { return this; }
}

class SomeBar extends Some<SomeFoo> {
    SomeFoo foo() { return new SomeFoo(); }
}

class SomeBaz extends Some<SomeBar> {
    SomeBar foo() { return new SomeBar(); }
}

// then in some method:
Some<SomeBar> a = new SomeBaz();
Some<SomeBar> b = a.bar();
SomeBar c = b.foo();

The code compiles with warnings but no errors, and throws a ClassCastException at runtime.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...