简体   繁体   English

Java:只能由超类调用的方法

[英]Java: method only callable by superclass

I would like to prevent a class from calling its own method. 我想防止一个类调用其自己的方法。 The method shall only be callable by its super class. 该方法只能由其超类调用。

Right now, I cannot think of any way to achieve this (cleanly). 现在,我想不出任何方法来(干净地)实现这一目标。 But maybe someone knows a solution? 但是也许有人知道解决方案?

In code: 在代码中:

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
    }
}

Edit: the explanation why I would like to do this: A is lets say a vehicle. 编辑:我为什么要这样做的解释:A是说车辆。 B can be a car or an airplane. B可以是汽车或飞机。 The method foo() would be startEngines(). 方法foo()将是startEngines()。 -> I want to make sure that the engines can only be started by calling the method barA().... does that make any sense? ->我想确保只能通过调用方法barA()来启动引擎。这有意义吗?

I guess this is similar to the problem AWT/Swing has with overriding the paint(Graphics g) method on a component (or onCreate(..) in Android Activities). 我猜这与AWT / Swing在组件上重写paint(Graphics g)方法(或Android Activities中的onCreate(..)遇到的问题类似。 Here you are overriding the paint method but you should never call it. 在这里,您将重写paint方法,但是永远不要调用它。

I think the best thing you can do is add documentation to the method to clarify that it should never be explicitly called by the subclasses OR re-evaluate your design. 我认为您可以做的最好的事情是向该方法中添加文档,以阐明该子类永远不要显式调用它,或者重新评估您的设计。

this answer has a good hint. 这个答案有一个很好的提示。

add below method in your class (class B): 在您的班级(班级B)中添加以下方法:

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

and change the foo method in class B to this: 并将in class Bfoo方法更改为:

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

you could put an interface as a member in the super class given to it via the constructor. 您可以将接口作为成员通过构造函数提供给它的超类。 the child class implements the method but can't call it except by making it static. 子类实现该方法,但只能通过使其静态化而不能调用它。

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
    }
}

Of course, this is not really what you asked for, but about as much as you can do about it in Java, I guess. 当然,这并不是您真正想要的,但是我猜想它几乎可以用Java完成。

Seeing the startEngines explanation, this solution might even suffice. 看到startEngines的说明,该解决方案甚至可以满足要求。 I guess you wouldn't care about the class calling its static methods, since they can only influence a static state, which is used seldom. 我猜您不会在意该类调用其静态方法,因为它们只能影响很少使用的静态状态。 The methods within the anonymous interface implementation can mutually call each other, but I guess that would be OK, since you only seem to be trying to prevent others to start the engines in some different way. 匿名接口实现中的方法可以相互调用,但是我想这样就可以了,因为您似乎只是想防止其他人以某种不同的方式启动引擎。

There is a way to do it, but you need to use Google Error Prone . 有一种方法可以做到,但是您需要使用Google Error Prone This is an extension of the Java compiler that aims to provide more and more helpful warnings and errors (similar to FindBugs and PMD, but with less false alarms). 这是Java编译器的扩展,旨在提供越来越多的有用警告和错误(类似于FindBugs和PMD,但虚假警报较少)。 I can only recommend it, it has already helped us to find some bugs. 我只能推荐它,它已经帮助我们发现了一些错误。

Specifically, it contains an annotation @ForOverride and an according compile-time check . 具体来说,它包含一个注释@ForOverride和一个相应的编译时检查 This annotation is meant to be used for protected methods that the sub-class and any other class should not call, but only the defining class. 此批注旨在用于子类和任何其他类不应该调用的受保护方法,而只能用于定义类。

So using 所以用

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

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

would exactly achieve what you want. 完全可以实现您想要的。

You can integrate Error Prone into most build systems like Maven and Ant. 您可以将Error Prone集成到大多数构建系统中,例如Maven和Ant。 Of course, it won't help if somebody compiles your source without Error Prone (for example in Eclipse), but using it in a continous-integration system would still allow you to find such issues. 当然,如果有人在没有Error Prone的情况下编译您的源代码(例如在Eclipse中),则无济于事,但是在连续集成系统中使用它仍然可以使您发现此类问题。 The source code still stays compatible with regular Java compilers (provided you have error_prone_annotations.jar on the class path), other compilers will simply not do the additional checks. 源代码仍与常规Java编译器保持兼容(前提是您在类路径上具有error_prone_annotations.jar ),其他编译器将完全不执行其他检查。

Considering your vehicle and engine scenario, I think you need to reconsider your design a bit. 考虑到您的车辆和发动机情况,我认为您需要重新考虑一下设计。 Your vehicle could be a car, aeroplane, etc but car, aeroplane, ... each have separate engines and therefore different startEngine method. 您的车辆可能是汽车,飞机等,但是汽车,飞机……每个都有独立的引擎,因此有不同的startEngine方法。 So declare your class vehicle as abstract like you did and class startEngine as abstract method . 因此,像您所做的那样,将类工具声明为抽象,将startEnginestartEngine为抽象方法。 Next , subclass Vehicle and implement startEngine in them , now you can invoke startEngine on the subclass instances 接下来,将Vehicle子类并在其中实现startEngine ,现在您可以在子类实例上调用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();
   }
}

Add Anonymouse inner class to barA method via Interface, so you will need to implement a method for foo() (functional interface). 通过Interface将Anonymouse内部类添加到barA方法中,因此您将需要实现foo()(功能接口)的方法。 It won't be part of Class B. 它不会属于B类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM