如何保护实现接口的方法不被覆盖?

How to protect a method implementing an interface from overriding?

我有接口:

public interface Doable {
    void doSomething();
}

和实现它的class:

public class DoJump() implements Doable {
    @Override
    private void doSomething() {
        fireJumpHandler();
    }
}

这是一个愚蠢的例子,但我想提出问题。

此代码无法编译,我在 Eclipse 中遇到错误 IDE:

Cannot reduce the visibility of the inherited method from Doable

我有一个声明方法的通用接口。该方法在具体 class 中被重写。我想避免另一个可以扩展这个 class (DoJump) 的 class,所以我想从 sub classes 中隐藏这个方法。我想使用 private 修饰符,但 Java 不允许我这样做。

为什么不可能,如何解决?

我想回答你的最后一个问题 "How to workaround it?",因为相关问题中没有对此进行描述。创建第二个接口 NotDoable,它根本没有声明 doSomething()。然后让你的 DoJump 实现这两个接口。给每个不应该覆盖 doSomething 接口 NotDoable 而不是真实类型 DoJump 的引用。然后他们就不会知道该对象确实可以 doSomething,他们不会知道每个 class 设计。当然,可以解决这个问题,但实际上可以解决所有问题。 class 这样设计更正确。这是一些代码:

public interface Doable {
    public void doSomething();
}

public interface NotDoable {

}

public class DoJump implements Doable, NotDoable {
    @Override
    public void doSomething() {
        System.out.println("hi");
    }

    public NotDoable meAsNotDoable() {
        return this;
    }

    public static void main(String[] args) {
        DoJump object = new DoJump();

        // This call is possible, no errors
        object.doSomething();

        NotDoable hidden = object.meAsNotDoable();

        // Not possible, compile error, the true type is hidden!
        hidden.doSomething();
    }
}

但如前所述,可以使用 if (hidden instanceof DoJump) { DoJump trueObject = (DoJump) hidden; } 解决此问题。但是,也可以通过反射访问私有值。

其他 classes 现在实现 NotDoable 而不是扩展 DoJump。如果你在这个界面声明了其他人应该知道的关于DoJump的一切,那么他们只能做他们应该做的。您可以调用此接口 IDoJump 和实现 class DoJump,一个常见的模式。

现在一样,更具体一点。

public interface IDog {
    public void bark();
}

public interface ICanFly {
    public void fly();
}

public class FlyingDog implements IDog, ICanFly {
    @Override
    public void bark() {
        System.out.println("wuff");
    }

    @Override
    public void fly() {
        System.out.println("Whuiiii");
    }

    public static void main(String[] args) {
        FlyingDog flyingDog = new FlyingDog();

        // Both works
        flyingDog.fly();
        flyingDog.bark();

        IDog dog = (IDog) flyingDog;

        // Same object but does not work, compile error
        dog.fly();

        ICanFly canFly = (ICanFly) flyingDog;

        // Same object but does not work, compile error
        canFly.bark();
    }
}

现在扩展 class。

public class LoudDog implements IDog {
    @Override
    public void bark() {
        System.out.println("WUUUUFF");
    }

    // Does not work, compile error as IDog does not declare this method
    @Override
    public void fly() {
        System.out.println("I wanna fly :(");
    }
}

最后要注意,如果其他人知道他们的IDog实际上是一个FlyingDog(并且他们施放了它),那么他们必须能够呼唤fly(),因为FlyingDog必须能飞。此外,它们 必须 能够覆盖行为,只要它们遵循其 method-signature 给出的 fly() 规范。想象一个叫做 PoorFlyingDogsubclass,他需要覆盖默认行为,否则他可以完美地飞行,但他是一个糟糕的飞行者。

总结:向别人隐瞒自己是DoJump,也隐瞒自己是Doable,假装只是NotDoable。或者对于动物,假装只是 IDog 而不是 FlyingDogICanFly。如果其他人不作弊(施法),他们将无法对你使用fly(),尽管你实际上可以飞行。

final 添加到 DoJump 声明以防止此 class 被覆盖(因此 doSomething() 也被覆盖)。

public final class DoJump implements Doable {
    @Override
    public void doSomething() {
        fireJumpHandler();
    }
}

如果你仍然需要能够继承DoJump但又不想doSomething()被覆盖,在方法签名中加上final修饰符

public class DoJump implements Doable {
    @Override
    public final void doSomething() {
        fireJumpHandler();
    }
}