不覆盖方法时使用super.method()?

SJ1*_*J19 5 java methods overriding super

始终使用super来调用超类之外的方法是常见的做法,即使我没有覆盖该方法也是如此?

假设

public class Parent{
    public void method() {

    }
}
Run Code Online (Sandbox Code Playgroud)

所以

public class Child extends Parent {
    public void someMethod() {
        super.method();
    }
}
Run Code Online (Sandbox Code Playgroud)

要么

public class Child extends Parent {
    public void someMethod() {
        method();
    }
}   
Run Code Online (Sandbox Code Playgroud)

感谢您的输入。

Tim*_*sen 5

调用super告诉JVM 显式查找方法的父类版本。继续您的示例,如果您只是打电话

method()
Run Code Online (Sandbox Code Playgroud)

Child在查看父类之前,JVM将首先在调用类中搜索方法(在本例中为)。另一方面,如果您致电

super.method()
Run Code Online (Sandbox Code Playgroud)

那么JVM将显式查看父类的实现,即使该类Child具有名为的方法method()

综合考虑这两个想法,super在打算调用父类的方法时,应该始终使用。如果您的类未覆盖该方法,则可以不使用进行调用super。但是,如果以后有人重构您的类并覆盖该方法,那么即使这样也会成为问题。

  • @砖你不明白我的答案。 (2认同)

Dur*_*dal 5

主要问题很容易回答:

即使我没有覆盖方法,也总是使用 super 来调用超类之外的方法是一种常见的做法吗?

不,这不是常见的做法。相反,这样做很危险。您通常调用方法,因为继承的主要目的是允许类覆盖方法以更改/扩展其行为。您通常不关心方法实际实现的级别。

明显的例外是当您自己重写方法并且您想要/需要父功能时。

现在到显式调用 super的危险的混乱部分:

public class CallSuper {

    static class Parent {
        public void foo() {
            System.out.println("Parent.foo");
        }

        /** 
         * Calls foo to do the main work
         */
        public void bar() {
            System.out.print
            foo();
        }
    }

    static class Child extends Parent {
        public void foo() {
            System.out.println("Child.foo");
        }

        public void bar() {
            super.foo();
        }
    }

    static class GrandChild extends Child {
        public void foo() {
            System.out.println("GrandChild.foo");
        }
    }

    public static void main(String[] args) {
        Parent p = new Parent();
        Parent c = new Child();
        Parent g = new GrandChild();

        System.out.print("Parent.foo() = ");
        p.foo();
        System.out.print("Child.foo() = ");
        c.foo();
        System.out.print("GrandChild.foo() = ");
        g.foo();

        System.out.print("Parent.bar() = ");
        p.bar();
        System.out.print("Child.bar() = ");
        c.bar();
        System.out.print("GrandChild.bar() = ");
        g.bar();
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您运行此示例,它将输出(为清楚起见添加了行号):

1 Parent.foo() = Parent.foo
2 Child.foo() = Child.foo
3 GrandChild.foo() = GrandChild.foo
4 Parent.bar() = Parent.foo
5 Child.bar() = Parent.foo
6 GrandChild.bar() = Parent.foo
Run Code Online (Sandbox Code Playgroud)

前四行并不奇怪,我们得到了 foo 在每一层实现的东西,分别是父母的 bar 调用它的 foo。它在第 5 行开始变得奇怪。 Child 通过调用 super.bar() 绕过它自己的 foo 覆盖,因此虽然它的 foo() 是专门的,但 bar() 不是。在第 6 行中,您会看到 GrandChild 继承了 Child 的这个奇怪之处,因此 Child 的 bar 中看起来有些无辜的 super.foo() 现在打破了 GrandChild 的期望,即它对 foo() 的覆盖也对所有 bar() 有效。

现在,如果您想象 foo() 和 bar() 实际上做了一些有用的事情,并且它们彼此之间具有有意义的关系,例如,您会相信(通过父母的文档或只是常识)覆盖 foo() 将改变bar() 的行为也是如此。孩子的“超级”正在打破这一点。

根据经验,如果您在实际覆盖“x()”之外的任何地方看到“super.x()”调用,则可能是潜在的意外发生。