【问题标题】:Java Inheritance: Overwritten or hidden methodsJava 继承:被覆盖或隐藏的方法
【发布时间】:2012-07-28 01:05:09
【问题描述】:

当一个类扩展另一个类时,它会继承超类的所有方法和变量。如果您在具有相同签名的子类中以不同方式定义方法和变量,则可以在子类中以不同方式使用。 现在 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 知道 更好,所以我想我只是不明白这篇文章。 当我从超类的对象调用实例方法时,它使用被覆盖的方法是不可能的。 所以我不明白为什么要区分覆盖和隐藏! 有人可以帮忙吗?

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

【问题讨论】:

  • 能否请您发布这些类的代码而不是描述它们?这样一来,您所谈论的代码类型就毫无疑问了。
  • stackoverflow.com/questions/10594052/… 是基本相同问题的一个很好的答案。
  • @JoachimSauer 好吧对不起,我下次贴代码!
  • @cups:您不必等待下一次,您可以直接在此处编辑问题。

标签: java inheritance overwrite


【解决方案1】:

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

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

请注意,您可以通过简单地编写程序并执行它来确认或证实您的疑问。

只有当您开始在对象实例上调用静态方法时,才会出现隐藏方法的问题。这是非常糟糕的做法,永远不应该这样做。如果您不遵守此规则,并且有以下情况:

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)。

【讨论】:

    【解决方案2】:

    根据你的例子举个例子:

    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 中的方法内调用,或使用限定名称。

    换个说法:

    • 覆盖方法意味着每当在派生类的对象上调用该方法时,都会调用新的实现。
    • 隐藏一个方法意味着在这个类的范围内(即在它的任何方法的主体,或者当使用此类的名称进行限定时)现在将调用一个完全不同的函数,需要限定才能从父类访问同名的静态方法。

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

    【讨论】:

      【解决方案3】:
      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

      【讨论】:

        猜你喜欢
        • 2017-09-21
        • 2011-02-05
        • 1970-01-01
        • 2015-12-26
        • 1970-01-01
        • 2016-01-24
        • 2013-08-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多