私は次の意味を理解しようとしていますか?
public class Bar<T extends Bar<T>> extends Foo<T> {
//Some code
}
このようなことを行うことの利点は何ですか(例:ユースケース?)。
これはかなり理論的な例ですが、次の場合に必要になる可能性があります。
public class Bar<T extends Bar<T>> extends Foo<T> {
private final T value;
public T getValue() { return value; }
public void method(T param) {
if (param.getValue().equals(someValue)) {
doSomething();
} else {
doSomethingElse();
}
}
}
param.getValue()
T が でない場合は呼び出すことができません。Bar
これはT extends Bar<T>
.
java.lang.Enum
これは、クラスの定義方法と非常によく似ています。
public abstract class Enum<E extends Enum<E>> implements Comparable<E> {
private final String name;
private final int ordinal;
protected Enum(String name, int ordinal) {
this.name = name; this.ordinal = ordinal;
}
public final String name() { return name; }
public final int ordinal() { return ordinal; }
public String toString() { return name; }
public final int compareTo(E o) {
return ordinal - o.ordinal;
}
}
このように定義されたクラスは抽象でなければならず、直接インスタンス化できないため、パターンは通常の列挙型が展開される方法と同様の構造で役立ちます。
// corresponds to
// enum Season { WINTER, SPRING, SUMMER, FALL }
final class Season extends Enum<Season> {
private Season(String name, int ordinal) { super(name,ordinal); }
public static final Season WINTER = new Season("WINTER",0);
public static final Season SPRING = new Season("SPRING",1);
public static final Season SUMMER = new Season("SUMMER",2);
public static final Season FALL = new Season("FALL",3);
private static final Season[] VALUES = { WINTER, SPRING, SUMMER, FALL };
public static Season[] values() { return VALUES.clone(); }
public static Season valueOf(String name) {
for (Season e : VALUES) if (e.name().equals(name)) return e;
throw new IllegalArgumentException();
}
}
本「Java Generics and Collection」の例。
Bar
基本的に、拡張するものに「対処」するタイプの種類を制限していますBar<T>
。この場合、 がBar
それ自体の拡張のみを処理していることを確認する必要があります。おそらく、 に対してプライベートなメソッドを呼び出しますBar
。Bar
簡単な例の 1 つは、このクラスを使用して一種のリンク リストを実装し、実行できる/実行する必要があることを実行しながらそれを反復処理することです。次のコードがあるとします。
public class Bar<T extends Bar<T>> extends Foo<T> {
private T next;
//Initialize next in constructor or somewhere else
private void doSomethingOnlyBarCanDo(){
//Do it...
}
public void iterate(){
T t = next;
while(t != null){
t.doSomethingOnlyBarCanDo();
t = t.next;
}
}
}
この種の構成では、インスタンスの「チェーン」を反復処理するのは非常に簡単Bar
です。各インスタンスには次への参照があるT
ためBar<T>
です。
典型的な使用例の 1 つは、Wrapper/Decorator パターンです。Bar
おそらくそれ自体T
を拡張するラップBar
。Foo
を扱う単なるパラメータ化されたクラスですT
。
public abstract class Foo<T> {
public abstract void foo(T t);
}
public class Bar<T extends Bar<T>> extends Foo<T> {
private T wrapped;
public Bar(T w) {
this.wrapped = w;
}
public abstract void foo(T t) {
// do something
}
}
私が言うことができる唯一のことは、<T extends Bar<T>>
これを使用することです。これT
は TypeBar<T>
になりました。つまり、で利用可能なすべてのメソッドにアクセスできるということですT
。.Bar
Bar
Bar<T>
T
では、用途は何ですか?
これは合成に使用できます。例えば
public class CustomList<T extends List<T>> {
T t;
T get(int index) {
//Some custom code here
return t.get(index);
}
}
Bar クラス内の Bar クラスメソッドに常にアクセスできるため、 T が Bar 型であることを伝える本当の利点はないため、あなたの例は少し間違っています