Java 在';你没有重写这个方法吗?

Java 在';你没有重写这个方法吗?,java,methods,overriding,super,Java,Methods,Overriding,Super,总是使用super调用超类以外的方法,即使我没有重写该方法,这是常见的做法吗 假定 public class Parent{ public void method() { } } 所以 或 感谢您的输入。调用super告诉JVM显式地查看父类的方法版本。继续你的例子,如果你打电话 method() JVM将首先在调用类中搜索该方法(在本例中为子类),然后再查看父类。另一方面,如果你打电话 super.method() 然后JVM将显式地查看父类的实现,即使Child有一个

总是使用super调用超类以外的方法,即使我没有重写该方法,这是常见的做法吗

假定

public class Parent{
    public void method() {

    }
}
所以


感谢您的输入。

调用
super
告诉JVM显式地查看父类的方法版本。继续你的例子,如果你打电话

method()
JVM将首先在调用类中搜索该方法(在本例中为
子类
),然后再查看父类。另一方面,如果你打电话

super.method()
然后JVM将显式地查看父类的实现,即使
Child
有一个名为
method()
的方法

将这两个概念放在一起,当您打算调用父类的方法时,可能应该始终使用
super
。如果您的类没有重写该方法,那么您可以在没有
super
的情况下调用。但是,如果以后有人重构您的类并重写该方法,即使这样也会出现问题

总是使用super从超类中调用方法是常见的做法吗?还是冗余代码

这不是多余的。它有一个调用父类方法的特殊用途(尽管您需要ovveriden)。当你不想要的时候,不要调用。如果当前类不是该类的子类,
super
将不适用于您

另外,如果调用重写的超级方法,它是使用超级方法还是最低的方法?(在继承树中)


重写的方法。因为您在类中重写了它。

调用超级方法与否完全取决于您尝试执行的操作。如果您想做父类所做的事情,再加上一些额外的操作,那么调用super方法是很好的。如果您在子实现中执行完全不同的操作,那么不要调用super方法。当您在类的层次结构中调用super方法时,它会调用层次结构中最接近您的子类的方法


在某些情况下,您可能有一个API,其中调用super方法是整个契约的一部分。克隆方法就是这种情况。

如果子版本方法与父版本方法相同,JVM将调用子版本而不是父版本(如果没有“super”)。如果您想确保孩子总是调用家长的版本方法,“super”关键字很有用。

前面的问题很容易回答:

总是使用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();
    }
}
如果运行此示例,它将输出(为清晰起见添加了行号):

前四行并不奇怪,我们得到了foo在每个级别上实现的东西,分别是父母的bar调用它的foo。在第5行开始变得奇怪。子对象通过调用super.bar()绕过其自身对foo的重写,因此虽然其foo()是专门化的,但bar()不是。在第6行中,您可以看到孙子继承了Child的这一怪癖,因此Child的bar中看起来有些天真的super.foo()现在打破了孙子的期望,即它对foo()的重写也对所有bar()有效

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


根据经验,如果您在实际重写“x()”之外的任何地方看到“super.x()”调用,这可能是一个潜在的意外事件。

如果您没有重写,让我们谈谈性能

如果在类中调用继承的方法,比如说,
methodInSuperclass()
,JVM将首先在类中查找该方法,然后在类层次结构中查找该方法,直到找到为止

使用
super.methodInSuperclass()
告诉JVM直接转到超类以查找该方法

因此,使用
super
关键字可以将性能提高几倍。这是难看的代码,但它不是多余的,因为它将带来一些性能改进


如果时间紧迫,可以考虑使用它。

谢谢你的回答,但如果我没有覆盖该方法,我仍然不知道是否应该使用super。Sky,这真的要看情况而定。如果你真的想用超类方法做点什么。我强烈推荐官方文件:。请阅读。您应该使用
super
。假设您或其他人后来决定重写
method()
。如果您假设仍在调用父类的方法(您不是),则代码可能会中断。@sᴜʀᴇsʜᴀᴛᴛᴀ 我不知道你说的“如果你真的想用超类方法做点什么”,我这么称呼它,显然我想用它?@TimBiegeleisen我也意识到了这一点,谢谢。你似乎是第一个不想把我弄糊涂的人:这是真的,但这似乎不适用于OP要求的情况。该示例表明OP询问如何从子方法调用super方法。这个答案是关于绕过子实现调用代码。@Brick您不理解我的答案。应该注意的是,如果您不打算重写某个方法(并控制超类),那么它将非常复杂
super.method()
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();
    }
}
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