11

I have an abstract class and one class that extend it, I have a method with same name in both class. I want to call the method in abstract class in another method of abstract class.

Controller.java

public abstract class Controller {

    public Result delete(Long id) {
        return this.delete(id, true);
    }
    public Result delete(Long id, boolean useTransaction) {
        // do something and return result
    }
}

FileGroup.java

public class FileGroup extends Controller {

    public Result delete(Long id, boolean central) {
        // do something
        return super.delete(id);
    }
}

super.delete call Controller.delete but this.delete(id, true) call delete in FileGroup instead of calling delete in Controller which is causing recursive infinite loop and stack overflows.

Pshemo
  • 122,468
  • 25
  • 185
  • 269
Mohse Taheri
  • 741
  • 1
  • 6
  • 23
  • @aioobe That's not entirely clear. Why did the OP not write `super.delete(id, central)`? It may be that the OP actually wants `delete` in `FileGroup` to call the one argument `delete` method in Controller which in turn calls the two argument `delete` in `Controller` without causing an infinite loop. – Paul Boddington Jan 11 '15 at 14:29
  • *"Why did the OP not write super.delete(id, central)?"* -- Because that would be a pointless override. *"[...] without causing an infinite loop."* -- Yes, that's what I would assume (and that's what I address in my answer). – aioobe Jan 11 '15 at 14:33
  • 1
    It wouldn't be a pointless override because of the `//do something`. – Paul Boddington Jan 11 '15 at 14:35
  • Fair enough. I still believe the OP intended for the Controller.delete(Long) to call Controler.delete(Long, boolean). – aioobe Jan 11 '15 at 14:43
  • @aioobe I think you're probably right. I was in the middle of writing the helper method solution when your answer appeared, so I'm not disagreeing I just think the question is unclear. – Paul Boddington Jan 11 '15 at 14:46
  • 5
    I think the root of your problem here is that you have violated a core OOP principle, the [Liskov Substitution Principle](http://en.wikipedia.org/wiki/Liskov_substitution_principle), by overriding `delete(Long,boolean)` but giving the second argument a different role in the subclass. That's simply not something a subclass should ever be doing, because the override (where the boolean means "central") breaks the contract of the method in the parent class (that the boolean is a flag to use a tx). Now callers will never know if they're calling it correctly without knowing the concrete type. – Mark Peters Jan 11 '15 at 15:17
  • @Mark Maybe you should post that as an answer – Sylvain Leroux Jan 11 '15 at 19:18
  • @Mark so having delete(Long id, boolean central) in FileGroup is against OOP? – Mohse Taheri Jan 12 '15 at 06:15
  • 1
    @Mohse: As long as you're giving a conflicting meaning to the arguments, yes. – Mark Peters Jan 12 '15 at 06:34
  • @MarkPeters thank you for useful information – Mohse Taheri Jan 12 '15 at 07:07
  • There is a lot of good information on this topic in previously answered questions. Here are few references. http://stackoverflow.com/questions/4836708/calling-base-class-overridden-function-from-base-class-method http://stackoverflow.com/questions/965690/java-optional-parameters – BateTech Jan 11 '15 at 15:12

2 Answers2

7

[...] but this.delete(id, true) call delete in FileGroup instead of calling delete in Controller.

Yes, all methods are virtual in Java, and there's no way to avoid that. You can however work around this by creating a (non overridden) helper method in Controller as follows:

public abstract class Controller {

    private Result deleteHelper(Long id, boolean useTransaction) {
        // do something and return result
    }

    public Result delete(Long id) {
        return deleteHelper(id, true);
    }
    public Result delete(Long id, boolean useTransaction) {
        return deleteHelper(id, useTransaction);
    }
}

By doing this you avoid having Controller.delete delegate the call to the subclass.

aioobe
  • 413,195
  • 112
  • 811
  • 826
  • thanks for answer I agree with you, but is there anything like 'this' to mention current class, if it was static I can just call Controller::delete(id, true) – Mohse Taheri Jan 12 '15 at 06:11
3

It's not entirely clear what your question is. If you are just trying to make the method delete in FileGroup call the method delete(id, true) in Controller without causing a stack overflow, you can just do this:

public class FileGroup extends Controller {

    public Result delete(Long id, boolean central) {
        // do something
        return super.delete(id, true);
    }
}

If your question is how to make the one-argument delete method in Controller call the two-argument delete method in Controller rather than the version in FileGroup, the answer is that you should use @aioobe's helper method solution.

Paul Boddington
  • 37,127
  • 10
  • 65
  • 116
  • thanks for answer it would solve my problem but I realy wants to know is there anything like 'this' to mention current class, if it was static I can just call Controller::delete(id, true) – Mohse Taheri Jan 12 '15 at 06:12
  • 1
    @MohseTaheri There is no way to invoke an instance method in `this` class and prevent versions in subclasses from being executed instead. The feature would be pointless anyway. As you are by definition in control of the current class, you can always just use aioobe's solution - call a private (or final) method from this class instead. – Paul Boddington Jan 12 '15 at 06:29