我发现以下使用泛型和继承的Java代码。我真的不理解以下代码片段的作用:
这段代码是做什么用的?
(我从MapDB中的DBMaker获取了这个代码)
class A<B extends A<B>> {
...
}
这段代码是做什么用的?
(我从MapDB中的DBMaker获取了这个代码)
class A<B extends A<B>> {
...
}
这个问题实际上包含两个部分:
1) 为什么要使用 B extends A
?
2) 在 B extends A<B>
中为什么要使用 A
作为泛型类型并将其赋值为 B
?
对于这些部分的答案如下:
1) 在这个例子中,类(A
)是一个构建器类(名为DBMaker
),因此大多数其方法返回一些类型,这些类型扩展了该构建器类的类型。这就解释了为什么B
应该扩展A
类。
2) 但是,如果我们隐藏第二部分中的...extends A<B>
,我们将得到一个普通的class A<B>
。所以A
具有类型变量B
的类型。因此,在...extends A<B>
中标记A为具有类型变量B
的类型A
。
这说明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;
}
}
class A<B extends A<B>> {
public B getMe(){
return (B) this;
}
}
getMe()
方法中返回类A
的子类。class C extends A<C> {
}
C c = new C();
c.getMe(); //returns C
所以我进行了一些测试来弄清楚这个问题,以下是我的测试用例,展示如何使用这样一个通用案例:
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.test.printB();