【问题标题】:Private Method overriding in javajava中的私有方法覆盖
【发布时间】:2017-11-02 06:55:27
【问题描述】:

我试图理解 java 中的方法覆盖。 明白私有方法不能被覆盖。

public class Superclass 
{
    private String name;

    Superclass(String name) {
        this.name=name;
    }

    private void printName(String name) {
        System.out.println("This is a Superclass output"+name);
    }
}

public class Subclass extends Superclass
{
    Subclass(String name) {
        super(name);
    }

    public void printName(String name) {
        System.out.println(name);
    }   
}   
public static void main (String[] args) {
    Superclass sb = new Subclass("Superclass");
    //System.out.println(sb.getClass().getName());
    sb.printName("this is super class variable");
}

我正在尝试执行这段 sn-p 代码 和输出:"This is a Superclass outputthis is super class variable"

请帮助我了解对象 sb 实际指的是哪个类。 当printName 在超类中公开时,我看到的输出是:

"this is super class variable"

还请帮助我理解为什么 sb 会根据修饰符 private 和 public 指向两个不同的类。

【问题讨论】:

标签: java inheritance


【解决方案1】:

覆盖是一种运行时(动态)多态性。我们不能覆盖私有方法。所以私有方法使用静态绑定。静态绑定方法不与特定对象关联,而是在 Type(Java 中的类)上调用。

当我们将父类方法设为public时,就会发生动态绑定。在运行时,对象的类型决定了要执行的方法。

【讨论】:

    【解决方案2】:
    Superclass sb = new Subclass("Superclass");
    

    这里Superclass 引用变量sb 将在Subclass 对象中搜索Superclass 对象,它会找到它,因为它自Subclass extends Superclass 以来就在那里。

    sb.printName("this is super class variable");
    

    这里因为sb指向Subclass对象,所以如果有一个被覆盖的方法,它就会执行那个方法。

    但是

    如果没有被覆盖的方法,它将始终执行Superclass 方法,因为引用类型是Superclass

    参考:http://www.codejava.net/java-core/the-java-language/12-rules-of-overriding-in-java-you-should-know

    Why parent class type reference variable having reference to child class object can't access child class's Methods

    【讨论】:

      【解决方案3】:

      您不能访问其类之外的私有方法。

      请看下表*:

                  | Class | Package | Subclass | Subclass | World
                  |       |         |(same pkg)|(diff pkg)| 
      ————————————+———————+—————————+——————————+——————————+————————
      public      |   +   |    +    |    +     |     +    |   +     
      ————————————+———————+—————————+——————————+——————————+————————
      protected   |   +   |    +    |    +     |     +    |         
      ————————————+———————+—————————+——————————+——————————+————————
      no modifier |   +   |    +    |    +     |          |    
      ————————————+———————+—————————+——————————+——————————+————————
      private     |   +   |         |          |          |    
      
      + : accessible
      blank : not accessible
      

      src

      所以如果你想打印"This is a Superclass outputthis is super class variable",你必须让你的超类的printName()至少包私有(=没有修饰符)。

      你的第二个问题:

      请帮助我了解对象 sb 实际指的是哪个类。当 printName 在超类中公开时,我看到的输出是:

      "这是超类变量"

      java 自动获取子类的功能,因为您在以下位置创建了它的实例:

      Superclass sb = new Subclass("Superclass");
      

      【讨论】:

        【解决方案4】:

        首先,您应该自己探索更多,这样当您的输出本身回答问题时,您就不需要问这样的问题。 您的问题是关于哪个对象而不是为什么会出现这种行为。 很好回答你的问题。考虑以下 2 个场景

        案例 1: Super super=new Super();
        案例 2: Super superSubclass=new Subclass(); //extends Super and instance refered by Super
        案例 3: Subclass subclass=new Subclass();// Referenced by own p>

        案例 1: 这个类不知道地球上的任何其他实现,所以它只能访问它自己在 Super 类中声明的方法( ALL 表示 ALL 包括 Private )。所以只要看看这个类就不会混淆。

        案例 2: 根据声明,子类是 Super 的扩展实现,实例是由 Super 引用创建的。 在这种情况下,superSubclass 可以访问扩展实现中的覆盖方法,除了 CASE 1。表示 SUPER 的所有方法 + SUBCLASS 中的覆盖方法

        案例3: 将其视为案例1。引用与它的实例相同,它可以访问其所有方法+其子类的非私有方法。

        我以与您问题相同的语气回答了这个问题,试图消除您的困惑。 但我认为您需要了解的主要内容是为什么这种行为最终会清除您的概念。 但是,正如我看到的那样,您是初学者,因此一旦开始像我上面提到的那样预测输出,您就会学习。

        干杯!

        【讨论】:

          【解决方案5】:

          因为private 方法的调用是在编译时确定的。 (顺便说一句,构造函数和super 方法也是在编译时确定的)。

          我会用字节码来解释。
          首先是源码:

          public class Q47069297 {
            public static void main(String[] args) {
              SuperClass sc = new SubClass();
              sc.print();
            }
          
            private static class SuperClass {
              private void print() {
                System.out.println("super");
              }
            }
          
            private static class SubClass extends SuperClass {
              private void print() {
                System.out.println("sub");
              }
            }
          }
          

          以及SuperClass.print的调用字节码:

          10  invokestatic xdean.stackoverflow.java.Q47069297$SuperClass.access$1(xdean.stackoverflow.java.Q47069297$SuperClass) : void [21]
          

          怎么了?我们打电话给print,但有SuperClass.access$1
          我们去SuperClass的字节码找到access$1

            static synthetic void access$1(xdean.stackoverflow.java.Q47069297.SuperClass arg0);
              0  aload_0 [arg0]
              1  invokespecial xdean.stackoverflow.java.Q47069297$SuperClass.print() : void [32]
              4  return
                Line numbers:
                  [pc: 0, line: 10]
          

          哇,真的有一种方法,一种叫做access$1的合成方法。所以我们发现类本身的私有方法调用只是java编译器的一个骗子。它在类中生成一个包友好的静态方法并调用它。所以源代码应该是:

          SuperClass sc = new SubClass();
          SuperClass.access$1(sc);// sc.print();
          

          它没有调用SubClass,因为它确实是一个静态方法调用。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-01-01
            • 2021-09-09
            • 2014-05-28
            • 2013-01-31
            • 2011-05-25
            • 2023-04-09
            相关资源
            最近更新 更多