Java继承:覆盖或隐藏的方法

时间:2012-07-30 11:06:11

标签: java inheritance overwrite

当一个类扩展另一个类时,它继承了超类的所有方法和变量。如果在具有相同签名的子类中以不同方式定义方法和变量,则可以在子类中以不同方式使用它们。 现在Oracle区分了覆盖和隐藏(http://docs.oracle.com/javase/tutorial/java/IandI/override.html)。 它表示实例方法会覆盖其超类的方法,而类方法会隐藏它。 “隐藏和覆盖之间的区别具有重要意义。被调用的被重写方法的版本是子类中的一个。被调用的隐藏方法的版本取决于它是从超类还是从子类调用的。”

假设我有2个课程是和可能。是延伸可能。 也许有String a。

class Maybe {
    String a;
    public static void printOut() {
        System.out.println("Maybe");
    }
    public void printAndSet() {
        a = "Maybe";
        System.out.println(a);
    }

}
class Yes extends Maybe {
    public static void printOut() {
        System.out.println("Yes");
    }
    pubilc void printAndSet() {
         a = "Yes";
    }
}
class Print{
    public static void mail(String[] args) {
        Maybe m = new Maybe();
        Yes y = new Yes();
        Maybe.printOut();
        Yes.printOut();
        m.printAndSet();
        y.printAndSet();
}

我说:它会打印出来 也许 是 也许 是

但是在我阅读了Oracle文章后,我认为它必须打印出来:

yes
yes
maybe
yes

因为实例方法会覆盖其超类方法。

我很确定我对输出是正确的,但我确信,Oracle也知道 更好,所以我想我只是不明白这篇文章。 当我从超类的对象调用实例方法时,它使用覆盖的方法是不正确的。 所以我不明白为什么要区分覆盖和隐藏! 有人可以帮忙吗?

编辑;插入代码而不是描述类!

3 个答案:

答案 0 :(得分:5)

根本无法覆盖静态方法。它们不是多态的,因为它们不作用于类的实例,而是作用于类本身。

如果您致电Maybe.printOut(),则会调用printOut()中定义的静态Maybe方法。 printOut()中定义的方法Yes这一事实无关紧要:除了名称之外,这两种方法没有任何共同之处。

请注意,您只需编写程序并执行即可确认或确认您的疑虑。

隐藏方法的问题仅在您开始在对象的实例上调用静态方法时发生。这是非常糟糕的做法,永远不应该这样做。如果您不遵守此规则,请执行以下操作:

Maybe m = new Maybe();
Maybe y = new Yes();

m.printOut(); // DON'T DO THAT: it should be Maybe.printOut();
y.printOut(); // DON'T DO THAT: it should be Maybe.printOut() or Yes.printOut();

结果将是maybe maybe,因为在静态方法的情况下,重要的是对象的具体类型(MaybeYes ),但他们的声明类型(MaybeMaybe)。

答案 1 :(得分:1)

public class Parent {

    public String test(){
        return "p";
    }

    public static String testStatic(){
        return "sp";
    }
}


public class Child extends Parent {

    public String test(){
        return "c";
    }

    public static String testStatic(){
        return "sc";
    }
}

public class Demo{

    public static void main(String[] args) {

        Parent p =new Parent();
        Child c = new Child();
        Parent pc = new Child();

        System.out.println(p.test());
        System.out.println(c.test());
        System.out.println(pc.test());

            //Although this is not the correct way of calling static methods
        System.out.println(p.testStatic());
        System.out.println(c.testStatic());
        System.out.println(pc.testStatic());
    }
}

OUTPUT将是: - (静态方法与实例方法)

点 C C SP SC 属

答案 2 :(得分:0)

根据您的示例采用以下示例:

public class SO11720216 {
    static class Maybe {
        public static void hidden() { System.out.println("static maybe"); }
        public void overwritten() { System.out.println("instance maybe"); }
        public void inherited() { hidden(); }
        public void called() { overwritten(); inherited(); }
    }
    static class Yes extends Maybe {
        public static void hidden() { System.out.println("static yes"); }
        public void overwritten() { System.out.println("instance yes"); }
    }
    public static void main(String[] args) {
        Maybe m = new Maybe();
        Yes y = new Yes();

        m.called(); /* prints:
                       instance maybe
                       static maybe
                    */

        y.called(); /* prints:
                       instance yes
                       static maybe
                    */
        Yes.hidden(); /* prints: static yes */
        y.hidden(); /* bad style! prints: static yes */
    }
}

每个派生类都会覆盖对overwritten的调用。因此每个方法都将使用属于当前对象的实现。另一方面,对hidden的调用将始终使用定义类的实现。因此,Maybe.called始终会调用Maybe.hidden,而永远不调用Yes.hidden。要致电Yes.hidden,您必须在Yes内的方法中使用,或使用限定名称。

用不同的词语表达:

  • 覆盖方法意味着只要在派生类的对象上调用方法,就会调用新的实现。
  • 隐藏方法意味着在此课程范围内对该名称的非限定性调用(如上例中的hidden()方法中的inherited()调用) (即在其任何方法的主体中,或者在使用此类的名称限定时)现在将调用一个完全不同的函数,需要一个资格来从父类访问同名的静态方法。

也许您的困惑来自于您假设覆盖以影响对该方法的所有调用,即使对于基类的对象也是如此。