2

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

假设我有 2 门课 Yes 和 Maybe。Yes 扩展了 Maybe。也许有字符串 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 知道得更好,所以我想我只是不理解这篇文章。当我从超类的对象调用实例方法时,它使用被覆盖的方法是不可能的。所以我不明白为什么要区分覆盖和隐藏!有人可以帮忙吗?

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

4

3 回答 3

5

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

如果调用Maybe.printOut(),它会调用中定义的静态printOut()方法MaybeprintOut()中还定义了一个方法这一事实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)。

于 2012-07-30T11:13:18.063 回答
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());
    }
}

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

p c c sp sc sp

于 2012-07-30T11:25:31.180 回答
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()) 现在将调用一个完全不同的函数,需要一个资格才能从父类访问同名的静态方法。

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

于 2012-07-30T11:19:09.197 回答