Подтвердить что ты не робот

Синтаксис дженериков Java

Я пытаюсь понять, что означает следующее:

public class Bar<T extends Bar<T>> extends Foo<T> {
    //Some code
}

В чем преимущество того, что вы делаете что-то вроде этого (например, прецедент?).

4b9b3361

Ответ 1

Это довольно теоретический пример, но в этом случае он может понадобиться:

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>.

Ответ 2

Это очень похоже на способ определения класса 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;
  }
}

Поскольку классы, определенные таким образом, должны быть abstract и не могут быть созданы напрямую, шаблон полезен в конструкциях, аналогичных тому, как расширяются обычные перечисления:

// 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".

Ответ 3

В основном вы ограничиваете типы типов, которые Bar будет "обрабатывать" на все, что расширяет Bar<T>. В этом случае вы хотите убедиться, что Bar имеет дело только с расширениями самого себя - возможно, вызовите метод, который закрыт для Bar. Один простой пример состоит в том, что вы можете использовать этот класс для реализации своего рода связанного списка и повторять его, выполняя то, что может/должно делать только Bar. Скажем, у вас есть следующий код:

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 extends Bar<T>, поэтому вы можете ссылаться на него как таковой.

Ответ 4

Один типичный вариант использования - шаблон 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 
    }
}

Ответ 5

Единственное, что я мог сказать: <T extends Bar<T>>, используя это, вы говорите, что T теперь имеет тип Bar<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);
    }
}

Ваш пример неверен, поскольку нет реального преимущества Telling, что T имеет Type Bar, поскольку у вас всегда будет доступ к методам класса Bar внутри класса Bar