【问题标题】:Java Generics and Inheritance recursionJava 泛型和继承递归
【发布时间】:2014-06-04 12:58:09
【问题描述】:

我遇到了以下使用泛型和继承的 Java 代码。我真的不明白以下 sn-p 做了什么:

class A<B extends A<B>> {
   ...
}

这段代码有什么作用?

(我从DBMaker in MapDB得到这个)

【问题讨论】:

标签: java generics


【解决方案1】:

几乎很清楚,问题实际上分为两部分:

1) 为什么是B extends A

2) 为什么A 里面的B extends A&lt;B&gt; 有泛型类型B

这些部分的答案是:

1) 特别是这个类 (A) 是 builder 类(称为DBMaker),所以它的大多数方法返回一些类型,扩展了这个构建器的类类型。这就解释了为什么B 应该扩展A 类。

2) 但是,实际上,如果我们在第二部分隐藏...extends A&lt;B&gt;,我们只会收到class A&lt;B&gt;。所以A 的类型变量为B。这就是为什么在...extends A&lt;B&gt; A 被标记为类型A 具有类型变量B

【讨论】:

  • 为什么这个被否决了?我正要发帖说我可以做这项工作(就像其他人所做的那样......),但我没有找到真正的用例。 Andremoniy 给出了这样一个构造的真实用例。 (为此+1)
【解决方案2】:

这表明A 需要派生定义才能做一些工作:

public abstract class A<T extends A<T>> {

   protected T instance;

   T getOne() {
       return instance;
   }
}

public class B extends A<B> {
   public B() {
       instance = this;
   }
}

public static void test() {
   B b = new B();
   b.getOne();
}

这在接口定义中最常用,人们希望在返回类型或参数中显式使用实现接口的类的实例,而不是接口本身:

public interface TimeSeries<T extends TimeSeries<T>> {
    T join(T ts);
}

public class DoubleTimeSeries implements TimeSeries<DoubleTimeSeries> {
    @Override
    public DoubleTimeSeries join(DoubleTimeSeries ts) {
        return null;
    }
}

【讨论】:

    【解决方案3】:

    所以我做了一些测试来解决这个问题,这是我的测试用例,看看如何使用这样一个通用案例:

    public class A<B extends A<B>> {
        int x = 10;
        B test;
    
        void printX() {
            System.out.println(x);
        }
    
        void setB(B b) {
            test = b;
        }
    
        void printB() {
            System.out.println(test);
        }
    }
    
    public class B extends A<B> {
    
    }
    
    public class Run {
        public static void main(String[] args) {
            A<B> test = new A<B>();
            B myB = new B();
            test.printX();
            test.setB(myB);
            test.printB();
            myB.printB();
    
        }
    }
    

    我希望代码可以不言自明。如果不发表评论,我将尝试解释发生了什么。看最后一行,myB.printB(),这里我们会得到一个 null,因为 B 还没有为 myB 设置,而只是为了测试。这表明我们可以无限递归到 A 内部(以及 B 内部)的 B 类。

    我们可以说:

    myB.test.printB();
    

    这将得到一个错误(空指针),但表明我们现在可以从 B 访问 A 类中的测试,并且我们可以使用任意多的情况递归地进行任意深度。所以 A 类的功能是无限多个 B 类的包装器。这有意义吗?

    【讨论】:

    • 投反对票时请留言!
    【解决方案4】:

    这使得定义方法返回类型时更容易,例如:

    class A<B extends A<B>> {
          public B getMe(){
                return (B) this;
          }
    }
    

    这告诉 Java 编译器你在 getMe() 方法中返回类 A 的子类。

    class C extends A<C> {
    
    }
    
    C c = new C();
    c.getMe(); //returns C
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-25
      • 1970-01-01
      相关资源
      最近更新 更多