让我们使用一个对链接有用的方法A
:
class A {
A foo() {
// do stuff
return this;
}
}
您现在可以执行a.foo().foo().foo()
(想想:构建器模式)。让B级扩展它:
class B extends A {
}
B b;
现在调用b.foo()
会返回实际类型B
,但会声明A
。因此我不能写:
B other = b.foo();
我必须写:
B other = (B) b.foo();
或覆盖B中的foo()
:
class B extends A {
@Override
B foo() {
super.foo();
return this;
}
}
有一个很好的方法吗?
答案 0 :(得分:1)
通过对超类实现额外的泛型方法as(type)
来实现这一点。这有助于为流畅的界面提供更好的演员。
class A {
public A foo() {
return this;
}
@SuppressWarnings("unchecked")
public <T extends A> T as(Class<T> clazz) {
return (T) this;
}
}
class B extends A {}
所以你可以写a.foo().as(B.class).methodOfB(..)
。而且您不需要在所有子类中重新实现foo()。
答案 1 :(得分:1)
很抱歉,但是你没有列出最好的方式:
B other = (B) b.foo();
这将是任何开发人员的解决方案,他们使用类A
和B
。
覆盖你,以便其他开发人员只需编写B other = b.foo();
但实际上编译器没有其他方法可以知道,
B
排序 A
B
兼容,因此您在实例化A
但未将其置于B
最后一个是您必须明确强制转换的原因。示例:
int myInt = 2;
short myShort = (short) myInt; // correct
虽然这有效,但编译器需要您明确,因为在许多情况下(当myInt
很大时),在转换为short
时会丢失精度/信息。
如果这个可行:
short myShort = myInt; // wrong
然后编译器会自己做出假设。但只有开发人员可以知道,myInt
是否会有一个大于short
的值。
答案 2 :(得分:1)
您可以声明class A
具有其实现类的泛型类型参数,foo()
可以返回此动态类型:
class A<T extends A<T>> {
@SuppressWarnings("unchecked")
T foo() {
// do stuff
return (T) this;
}
}
class B extends A<B> {
B bar() {
// do other stuff
return this;
}
}
在此之后,以下内容有效:
B b = new B();
b.foo().bar();
答案 3 :(得分:0)
我认为执行此操作的好方法是将引用保留为类型A
,因为这是具有所需功能的最不具体的类:
A other = b.foo();
如果B包含一些必需的功能,则只应转换为类型B:
B another = (B)A;
another.somethingElse();
这与以下逻辑相同:
List<String> myList = new ArrayList<>();
比以下更令人满意:
ArrayList<String> myList = new ArrayList<>();