Java: 方法只能由超类调用

Java: method only callable by superclass

我想阻止 class 调用它自己的方法。该方法只能由其超级 class.

调用

现在,我想不出有什么办法(干净利落地)实现这一点。但也许有人知道解决方案?

在代码中:

public abstract class A {
    protected abstract void foo();

    private void barA() {
        //do smth
        foo();
    }
}

public class B extends A {
    @Override
    protected void foo() {
        //do smth
    }

    private void barB() {
        //must not be able to call foo() here
    }
}

编辑:解释我为什么要这样做: A 可以说是一辆车。 B可以是汽车或飞机。 foo() 方法将是 startEngines()。 -> 我想确保只能通过调用 barA() 方法来启动引擎....这有意义吗?

我想这类似于 AWT/Swing 覆盖组件上的 paint(Graphics g) 方法(或 Android 活动中的 onCreate(..) )的问题。此处您覆盖了 paint 方法,但您永远不应调用它。

我认为您能做的最好的事情是向该方法添加文档以阐明它 永远不会 被子类显式调用或重新评估您的设计。

this answer 有一个很好的提示。

在您的 class (class B) 中添加以下方法:

public static String getMethodName(final int depth)
{
  final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
  return ste[ste.length - 1 - depth].getMethodName();
}

并将 foo 方法 in class B 更改为:

   @Override
    protected void foo() {
        //....
        if (getMethodName(0)=="barB"){
           // tell you are not able to call barB
        }
    }

您可以将接口作为成员放入通过构造函数提供给它的超级 class 中。 child class 实现了该方法,但不能调用它,除非将其设为静态。

interface Foo {
    void stopEngines();
    void startEngines();
}

abstract class Base {
    final private Foo foo;

    public Base(final Foo foo) {
        this.foo = foo;
    }
    private void barA() {
        // do smth
        foo.startEngines();
    }
}

class Child extends Base {
    public Child() {
        super(new Foo() {
            boolean engineRunning;
            @Override
            public void stopEngines() {
                this.engineRunning = false;
            }

            @Override
            public void startEngines() {
                this.engineRunning = true;
            }
        });
    }
    private void barB() {
        // can't call startEngines() or stopEngines() here
    }
}

class Child2 extends Base {
    public Child2() {
        super(new Foo() {
            @Override
            public void stopEngines() {
                stopEngines();
            }

            @Override
            public void startEngines() {
                startEngines();
            }
        });
    }
    static void stopEngines() {
        // influence some static state?
    }
    static void startEngines() {
        // influence some static state?
    }
    private void barB() {
        // can call stopEngines() and startEngines(), but at least they have to be static
    }
}

当然,这并不是您真正要求的,但我想您在 Java 中可以做的差不多了。

看到startEngines的解释,这个解决方案可能就足够了。 我猜你不会关心 class 调用它的静态方法,因为它们只能影响很少使用的静态。匿名接口实现中的方法可以相互调用,但我想这没问题,因为你似乎只是想阻止其他人以某种不同的方式启动引擎。

有一种方法可以做到,但你需要使用Google Error Prone。这是 Java 编译器的扩展,旨在提供越来越多有用的警告和错误(类似于 FindBugs 和 PMD,但误报更少)。我只能推荐它,它已经帮助我们找到了一些错误。

具体来说,它包含一个注解@ForOverride and an according compile-time check。此注释旨在用于子 class 和任何其他 class 不应调用的受保护方法,而只能用于定义 class.

所以使用

public abstract class A {
    @ForOverride
    protected abstract void foo();

    private void barA() {
        //do smth
        foo();
    }
}

完全可以达到你想要的效果。

您可以将 Error Prone 集成到大多数构建系统中,例如 Maven 和 Ant。当然,如果有人在没有 Error Prone 的情况下编译您的源代码(例如在 Eclipse 中),这将无济于事,但是在持续集成系统中使用它仍然可以让您发现此类问题。源代码仍然与常规 Java 编译器兼容(前提是 class 路径上有 error_prone_annotations.jar),其他编译器将不会进行额外检查。

考虑到您的车辆和引擎场景,我认为您需要重新考虑一下您的设计。 您的交通工具可以是汽车、飞机等,但汽车、飞机……每个都有独立的引擎,因此 startEngine 方法不同。因此,像您所做的那样将您的 class 车辆声明为抽象的,并将 class startEngine 声明为抽象方法。接下来,subclass Vehicle 并在其中实现 startEngine,现在您可以在 subclass 实例

上调用 startEngine
abstract class Vehicle{
    abstract void startEngine();
}

public class Car extends Vehicle{
   public void startEngine(){  
      //implementation  
   }  
   public static void main(String[] arg){
       Vehicle v=new Car();
       v.startEngine();
   }
}

通过接口将 Anonymouse inner class 添加到 barA 方法,因此您需要为 foo() (功能接口)实现一个方法。它不会成为 Class B.

的一部分