强制返回类型缩小Java?

时间:2015-01-16 17:43:40

标签: java inheritance covariance narrowing

可以在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()并违反模式。

4 个答案:

答案 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以保留泛型中的多态性。