Javagenerics和inheritance递归
我遇到了以下使用generics和inheritance的Java代码。 我真的不明白以下代码片段的作用:
class A<B extends A> { ... }
这段代码有什么作用?
(我从MapDB中的DBMaker那里得到了这个)
这几乎是清楚的,问题实际上分为两部分:
1)为什么B extends A
?
2)为什么A
内部B extends A
具有通用类型B
?
这些部分的答案将是:
1)在特定示例中,此类( A
)是构建器类(称为DBMaker
),因此其大多数方法返回某种类型,这会扩展此构建器的类类型。 这解释了为什么B
应该扩展A
类。
2)但是,实际上,如果我们将隐藏第二部分...extends A
,我们将只收到class A
。 因此A
具有B
类型的变量。 这就是为什么在...extends A
A被标记为具有类型变量B
类型A
这告诉A
需要派生定义才能做一些工作:
public abstract class A> { protected T instance; T getOne() { return instance; } } public class B extends A { public B() { instance = this; } } public static void test() { B b = new B(); b.getOne(); }
这在接口定义中最常用,其中一个想要显式地使用在返回类型或参数中实现接口的类的实例,而不是接口本身:
public interface TimeSeries> { T join(T ts); } public class DoubleTimeSeries implements TimeSeries { @Override public DoubleTimeSeries join(DoubleTimeSeries ts) { return null; } }
所以我做了一些测试来解决这个问题,这是我的测试用例,看看如何使用这样的通用案例:
public class A> { 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 { } public class Run { public static void main(String[] args) { A test = new A(); B myB = new B(); test.printX(); test.setB(myB); test.printB(); myB.printB(); } }
我希望代码可能是自我解释的。 如果不发表评论,我会尝试解释发生了什么。 查看最后一行myB.printB(),这里我们将得到一个null,因为尚未为myB设置B,但仅用于测试。 这表明我们可以无限递归到A中的B类(对于那个问题,在B内)。
我们可以说:
myB.test.printB();
这将得到一个错误(空指针),但表明我们现在可以从B中访问A类中的测试,并且我们可以根据需要递归到我们想要的尽可能多的情况。 所以A类的函数作为无限多B类的包装器。 这有意义吗?
这使得在定义方法返回类型时更容易,例如:
class A> { public B getMe(){ return (B) this; } }
这告诉Java编译器你在getMe()
方法中返回类A
的子类。
class C extends A { } C c = new C(); c.getMe(); //returns C