1

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. B can be a car or an airplane. The method foo() would be startEngines(). -> I want to make sure that the engines can only be started by calling the method barA().... does that make any sense?

user3726374
  • 583
  • 1
  • 4
  • 24
  • This is not possible in Java. I'd advice you to re-thing your design. – Konstantin Yovkov Apr 02 '15 at 12:03
  • 1
    As other have pointed out; this is not possible in Java. And sorry to say that, the whole idea is a pretty bad design. But you are welcome to explain "why" you think you need this - I am sure there will be better ways to whatever it is that you actually want to achieve. – GhostCat Apr 02 '15 at 12:10
  • Okay, I edited my post to explain my idea. – user3726374 Apr 02 '15 at 12:14

6 Answers6

0

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). Here you are overriding the paint method but you should never call it.

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.

Subler
  • 657
  • 6
  • 11
0

this answer has a good hint.

add below method in your class (class 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:

   @Override
    protected void foo() {
        //....
        if (getMethodName(0)=="barB"){
           // tell you are not able to call barB
        }
    }
Community
  • 1
  • 1
void
  • 7,760
  • 3
  • 25
  • 43
0

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.

Seeing the startEngines explanation, this solution might even suffice. 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.

muued
  • 1,666
  • 13
  • 25
0

There is a way to do it, but you need to use 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). 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. 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. 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. 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.

Philipp Wendler
  • 11,184
  • 7
  • 52
  • 87
0

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. So declare your class vehicle as abstract like you did and class startEngine as abstract method . Next , subclass Vehicle and implement startEngine in them , now you can invoke startEngine on the subclass instances

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();
   }
}
Sarabjeet
  • 264
  • 2
  • 17
0

Add Anonymouse inner class to barA method via Interface, so you will need to implement a method for foo() (functional interface). It won't be part of Class B.

Laszlo Lugosi
  • 3,669
  • 1
  • 21
  • 17