问题 从实际类中具有相同名称的抽象类中的另一个方法调用方法


我有一个抽象类和一个扩展它的类,我在这两个类中都有一个同名的方法。 我想在抽象类的另一个方法中调用抽象类中的方法。

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 呼叫 Controller.delete 但 this.delete(id, true) 呼叫 delete 在 FileGroup 而不是打电话 delete 在 Controller 这导致递归无限循环和堆栈溢出。


3238
2018-01-11 14:09


起源

@aioobe这还不完全清楚。为什么OP不写 super.delete(id, central)? OP可能真的想要 delete 在 FileGroup 调用一个参数 delete Controller中的方法,它又调用两个参数 delete 在 Controller 没有造成无限循环。 - Paul Boddington
“为什么OP不写super.delete(id,central)?”  - 因为这将是一个毫无意义的覆盖。 “[......]没有造成无限循环。”  - 是的,这就是我的假设(这就是我在答案中提到的)。 - aioobe
由于这个原因,它不会是一个毫无意义的覆盖 //do something。 - Paul Boddington
我认为你问题的根源在于你违反了核心OOP原则 利斯科夫替代原则,通过压倒 delete(Long,boolean) 但是给第二个参数在子类中扮演不同的角色。这根本不是子类应该做的事情,因为覆盖(布尔意味着“中心”)打破了父类中方法的约定(布尔值是使用tx的标志)。现在,在不知道具体类型的情况下,呼叫者永远不会知道他们是否正确地调用它。 - Mark Peters
@Mohse:只要你给论点带来冲突的意义,是的。 - Mark Peters


答案:


[...]但是 this.delete(id, true) 呼叫删除 FileGroup 而不是在中调用删除 Controller

是的,所有方法都是Java虚拟的,没有办法避免这种情况。但是,你可以通过创建一个(非重写的)辅助方法来解决这个问题 Controller 如下:

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

通过这样做你可以避免 Controller.delete 委托调用子类。


7
2018-01-11 14:12



谢谢你的回答我同意你的意见,但是有什么比'this'提及当前的类,如果它是静态的我可以调用Controller :: delete(id,true) - Mohse Taheri
不。你必须做这种解决方法。 - aioobe


你的问题是什么并不完全清楚。如果你只是想制作这个方法 delete 在 FileGroup 打电话给方法 delete(id, true) 在 Controller 在不导致堆栈溢出的情况下,您可以这样做:

public class FileGroup extends Controller {

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

如果你的问题是如何做出一个论点 delete 方法 Controller 称之为两个论点 delete 方法 Controller 而不是版本 FileGroup,答案是你应该使用@ aioobe的帮助方法解决方案。


3
2018-01-11 14:55



谢谢你的回答它会解决我的问题,但我真的想知道是否有类似'this'提及当前类,如果它是静态的我可以调用Controller :: delete(id,true) - Mohse Taheri
@MohseTaheri无法调用实例方法 this 类和防止子类中的版本被执行。无论如何,这个功能毫无意义。按照您的定义控制当前类,您可以随时使用aioobe的解决方案 - 从此类调用私有(或最终)方法。 - Paul Boddington