【问题标题】:How to apply more constraints on an interface declaration in Java?如何对 Java 中的接口声明应用更多约束?
【发布时间】:2015-05-13 13:01:23
【问题描述】:

假设我有以下界面:

interface Mammal {
    void marry(Mammal m);
    Mammal giveBirthTo();
}

但是,这并不能完全说明我想要什么。

显然,人不能嫁给狗,也不能生猫。那么如何将这些信息嵌入到接口中,以便在实现时可以自动更改输入类型和输出类型?

【问题讨论】:

    标签: java generics interface


    【解决方案1】:

    您可以使用泛型并更改您的设计。

    以下内容:

    interface Marriable<T extends Mammal> {
        void marry(T sweetHalf);
        T giveBirthTo();
    }
    

    ... 其中Mammal 是您的顶级接口或抽象类,HumanDogUnicorn 等扩展/实现它。

    【讨论】:

    • 接口不应该命名为Mammal吗?没有理由再添加一个。
    • @RafaelWinterhalter 正如我提到的那样,您可以有一个 Mammal 接口或抽象类来抽象该特定继承链中的顶级动物。 Marriable 接口将定义与您的物种之一结婚的合同。
    • 您不需要Marriable 接口。您可以按照我刚刚添加的答案中的建议简单地创建一个递归类型。
    • @RafaelWinterhalter 你的方法中的问题是它混合了结婚和物种的范围。 “哺乳动物”的例子不是最好的解释这一点,但想象一下HappyToBeSingleHumanJustPlainUglyHuman。他们会扩展/实现Mammal,但不会扩展/实现Marriable
    • 但这不是 OP 所要求的,也与问题解决方案无关,因为即使不使用泛型,也可以将 Mammal 接口重构为这样的层次结构。我所说的是你的解决方案添加了一个额外的间接。
    【解决方案2】:

    您可以使用递归类型变量来生成您的接口:

    interface Mammal<T extends Mammal<T>> {
      void marry(T m);
      T giveBirthTo();
    }
    

    这样,Java 编译器可以为您提供一定的验证级别。但是请注意,这种方法仍然容易被滥用。例如:

    class Cat implements Mammal<Cat> {
      @Override void marry(Cat cat) { ... }
      @Override Cat giveBirthTo() { ... }
    }
    
    class Dog implements Mammal<Cat> { // implements wrong interface
      @Override void marry(Cat cat) { ... }
      @Override Cat giveBirthTo() { ... }
    }
    

    编译器只能确保您通过同一接口的某些子类型实现Mammal 接口,而不是通过实现它的特定类。后一种类型约束不能用 Java 编程语言表达。

    【讨论】:

    • 为了您的谷歌搜索乐趣,这称为 F-bounded quantification
    【解决方案3】:

    泛型。试试

     private static interface Race {
    }
    
    private static class Human implements Race {}
    private static class Canine implements Race {}
    
    private static interface Being<R extends Race> {
        void marry(Being<R> other);
        Being<R> giveBirthTo();
    }
    
    private void tryMe() {
        Being<Human> aHuman = new Being<Human>() {
    
            @Override
            public void marry(Being<Human> other) {
            }
    
            @Override
            public Being<Human> giveBirthTo() {
                return null;
            }
        };
    
        Being<Canine> aCanine = new Being<Canine>() {
    
            @Override
            public void marry(Being<Canine> other) {
            }
    
            @Override
            public Being<Canine> giveBirthTo() {
                return null;
            }
        };
    
        aHuman.marry(aCanine); // not possible
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多