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

时间:2016-07-13 12:40:40

标签: java visibility

我有界面:

2016-07-13T12:13:28.80+0000 [App/0]      OUT stderrsudo: no tty present and no askpass program specified
2016-07-13T12:13:28.80+0000 [App/0]      OUT E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)
2016-07-13T12:13:28.80+0000 [App/0]      OUT E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?

以及实现它的类:

public interface Doable {
    void doSomething();
}

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

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

  

无法降低继承方法的可见性   可行

我有一个声明方法的通用接口。具体类中重写此方法。我想避免另一个可以扩展这个类(public class DoJump() implements Doable { @Override private void doSomething() { fireJumpHandler(); } } )的类,所以我想从子类中隐藏这个方法。我想使用DoJump修饰符,但Java不允许我这样做。

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

2 个答案:

答案 0 :(得分:3)

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

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; }解决此问题。但是,人们也可以通过反思访问私人价值观。

其他课程现在实施NotDoable而不是扩展DoJump。如果您在此界面中声明其他人应该知道的关于DoJump的所有内容,那么他​​们只能做他们应该做的事情。您可以将此接口称为IDoJump和实现类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();
    }
}

现在是扩展类。

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(他们投了它们),那么他们必须能够致电{ {1}} fly()必须能够飞行。此外,只要它们遵循FlyingDog给出的fly()规范,必须才能覆盖该行为。想象一个名为method-signature的{​​{1}},他需要覆盖默认行为,否则他可以完美地飞行,但他是一个可怜的传单。

总结:向其他人隐瞒您实际上是subclass,同时隐藏您是PoorFlyingDog,假装只是DoJump。或者与动物一起,假装只是Doable而不是NotDoableIDog。如果其他人不作弊(施法),他们将无法使用FlyingDog,尽管你实际上可以飞行。

答案 1 :(得分:2)

final添加到DoJump声明,以防止覆盖此类(因此也应覆盖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();
    }
}