【问题标题】:Java generics syntaxJava 泛型语法
【发布时间】:2012-08-29 09:11:44
【问题描述】:

我正在尝试理解以下内容的含义?

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

做这样的事情有什么好处(例如用例?)。

【问题讨论】:

    标签: java generics


    【解决方案1】:

    这与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 泛型与集合”一书中的示例。

    【讨论】:

      【解决方案2】:

      这是一个相当理论的例子,但在这种情况下你可能需要它:

      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();
              }
          }
      }
      

      如果 T 不是 Bar,您将无法调用 param.getValue(),这是因为 T extends Bar&lt;T&gt;。

      【讨论】:

      • @maba 看起来我在中途改变了我的 ming ;-) 修正了。
      • 请注意,Bar 应该是抽象的,因为它永远不能直接使用。在这里查看我的答案:stackoverflow.com/questions/7354740/…
      • @PaulBellora 确实如此。 java.lang.Enum 的定义非常相似:public abstract class Enum&lt;E extends Enum&lt;E&gt;&gt; implements Comparable&lt;E&gt;
      • @dcernahoschi 这将是一个很好的答案。刚看到你做了一个。为此 +1。
      • @PaulBellora @dcernahoschi static &lt;T extends Bar&lt;T&gt;&gt; Bar&lt;T&gt; createBar() { return new Bar&lt;T&gt;(); } 怎么样?
      【解决方案3】:

      我唯一能说的是&lt;T extends Bar&lt;T&gt;&gt; 使用这个你告诉T 现在是Bar&lt;T&gt; 类型,这意味着T 是Bar 所以你可以访问Bar 可用的所有方法,否则如果你只做Bar&lt;T&gt;,你将无法访问它,因为T那时是通用的。

      那有什么用呢?

      你可以用它来作曲。例如

      public class CustomList<T extends List<T>> {
          T t;
      
          T get(int index) {
              //Some custom code here
              return t.get(index);
          }
      }
      

      您的示例有点错误,因为告诉 T 属于 Bar 类型并没有真正的优势,因为您将始终可以访问 Bar 类中的 Bar 类方法

      【讨论】:

        【解决方案4】:

        您基本上将Bar 将“处理”的类型限制为扩展Bar&lt;T&gt; 的任何类型。在这种情况下,您要确保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 扩展 Bar&lt;T&gt;,所以你可以这样引用它。

        【讨论】:

        • 我总是可以调用doSomethingOnlyBarCanDo() 方法,因为它在同一个类中。那么它有什么特别之处呢?
        • @AmitD 如果t 是Bar,您只能调用t.doSomethingOnlyBarCanDo();。
        • @student 如果这样做可以使您的代码更易于维护和理解,或者如果它隐藏了不应暴露给外部类的复杂内容,则通常是一种很好的做法。我个人喜欢对泛型施加限制,因为它可以让外部开发人员更好地了解该类的用途。真正使这件事变得混乱的一件事是学术界使用“Foo”和“Bar”作为合法的类名。它们没有提供任何关于这些类应该做什么的提示,它们只告诉你语法的能力。
        • @assylias 我对示例不满意,仅此而已。所以我给了我的。:)
        【解决方案5】:

        一个典型的用例是包装器/装饰器模式。 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 
            }
        }
        

        【讨论】:

        • 这也适用于public class Bar&lt;T&gt; extends Foo&lt;T&gt;
        猜你喜欢
        • 1970-01-01
        • 2015-10-08
        • 1970-01-01
        • 1970-01-01
        • 2010-09-16
        • 1970-01-01
        • 2015-08-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多