可以在Java中覆盖覆盖方法中的返回类型。
但是在声明中是否有可能强迫这种缩小?
例如,这可能在模式中很好,其中内部类与外部类同时进行子类化:
public class Try_ForceNarrow {
public interface IMember {
}
public interface Container<M extends IMember> {
M createMember();
}
public static class A implements Container<A.Member> {
@Override
public Member createMember() {
return new Member();
}
public class Member implements IMember {
}
}
public static class B extends A implements Container<B.Member> {
@Override
public Member createMember() {
return new Member();
}
public class Member extends A.Member {
}
}
public static void main(String[] args) {
}
}
此代码编译失败,错误为“接口容器不能使用不同的参数多次实现”。
如何避免这种情况?
当然,我可以写
public static class B extends A {
@Override
public Member createMember() {
return new Member();
}
public class Member extends A.Member {
}
}
但是这样我可以忘记覆盖createMember()
并违反模式。
答案 0 :(得分:0)
那么A<T> implements Container<T>
呢?您可以根据需要进一步限制T ...
答案 1 :(得分:0)
在我看来,您希望每个子类C
都有一个createMember
工厂方法,该方法返回一个具有相同类型的新对象。问题是如果C1
提供的工厂方法返回C1
,然后C2
延伸C1
,则无法强制C2
提供自己的工具方法方法 - 它可以从C1
继承一个。
我不认为有一个解决方案可以在编译时捕获错误,但也许你可以做一些在运行时捕获错误的东西:
abstract class MemberBase {
protected abstract MemberBase doCreateMember();
protected abstract Class<?> memberClass();
public MemberBase createMember() {
MemberBase result = doCreateMember();
if (result.getClass() != memberClass()) {
throw new RuntimeException("createMember returned the wrong class");
}
return result;
}
}
public static class A extends MemberBase {
@Override
protected Member doCreateMember() {
return new Member();
}
@Override
protected Class<?> memberClass() {
return Member.class;
}
public class Member implements IMember {
}
}
public static class B extends A {
// If you forget to define this, the doCreateMember in A will be
// inherited, but it will return the wrong class and lead to a
// run-time exception
@Override
protected Member doCreateMember() {
return new Member();
}
@Override
protected Class<?> memberClass() {
return Member.class;
}
public class Member extends A.Member {
}
}
我没有对此进行测试,但我不确定它是否能满足您的需求。另外我可能有一些错误的语法。但也许这个,或者它的修改可能是有用的。
答案 2 :(得分:0)
我相信这符合你的目标。
您可以创建一个实现Container
的新抽象类,它允许您不断扩展或缩小泛型,但是您需要声明每个类是静态的:
class Try_ForceNarrow {
public interface IMember {
}
public interface Container<M extends IMember> {
M createMember();
}
//The abstract class that lets you continually extend or "narrow"
public static abstract class A<E extends A.Member> implements Container<E> {
public static class Member implements IMember {
}
}
//Here is the first class that extends the Abstract Class A
public static class B extends A<B.Member> { //This class now Implements Container<B.Member>
@Override
public Member createMember() {
return new Member();
}
//Since this is the first extension we will extend A.Member
public static class Member extends A.Member {
}
}
//This is an additional class that extends A but we want to extend the functionality of B.Member also.
public static class C extends A<C.Member> { //This class now Implements Container<C.Member>
@Override
public Member createMember() {
return new Member();
}
//C.Member properly extends B.Member
//if this class is going to be extended this needs to be static
public class Member extends B.Member {
}
}
}
当然,根据您的要求,如果您删除
@Override
public Member createMember() {
return new Member();
}
从扩展的子类中,您会收到编译错误。
答案 3 :(得分:-1)
当然它会失败,您的班级A
会实施Container<A.Member>
,但您的班级B
会延伸A
,但也会实施Container<B.Member>
,就像class B extends A implements Container<A.Member> Container<B.Memeber>
1}},就编译器而言,由于类型擦除,Container<A.Member>
和Container<B.Member>
之间没有区别,编译后,所有泛型信息都将丢失,因此没有&lt; ...... &GT;在类型擦除之后,只存在它们的上限和下限,你的类型参数是无界的,所以它们将擦除到相同的类型,在擦除之后,你的类B
字面上看起来像class B extends A implements Container Container
这是根本错误的。您可以缩小覆盖的返回类型(称为协变返回类型),这也将在VM中创建bridge method
以保留泛型中的多态性。