【问题标题】:When overriding a method, why can I increase access but not decrease it?覆盖方法时,为什么我可以增加访问权限但不能减少访问权限?
【发布时间】:2011-10-14 15:53:49
【问题描述】:

为什么 Java 指定重写方法的访问说明符可以允许比重写方法更多但不能更少的访问?例如,超类中的受保护实例方法可以在子类中公开,但不能设为私有。

【问题讨论】:

  • 使用通用描述:B extends A if B is-a A。所以如果A可以做action()B is-a A,那么B应该也可以做action()
  • 抽象 A 怎么样?

标签: java inheritance access-modifiers


【解决方案1】:

因为它会很奇怪:

class A {
    public void blah() {}
}

class B extends A {
    private void blah() {}
}


B b = new B();
A a = b;
b.blah();  // Can't do it!
a.blah();  // Can do it, even though it's the same object!

【讨论】:

    【解决方案2】:

    想象一下这两个类:

    public class Animal {
      public String getName() { return this.name; }
    }
    
    public class Lion extends Animal {
      private String getName() { return this.name; }
    }
    

    我可以写这段代码:

    Animal lion = new Lion();
    System.out.println( lion.getName() );
    

    而且它必须是有效的,因为在 Animal 方法 getName() 是公开的,即使它在 Lion 上是私有的>。所以不可能让子类上的东西不那么明显,因为一旦你有了超类引用,你就可以访问这些东西。

    【讨论】:

    • 这就是里氏替换原则的意义所在。
    【解决方案3】:

    因为子类是超类的特化,或者换句话说,它是超类的扩展。

    想象一下 toString 方法。所有 Java 对象都有它,因为 Object 类有它。想象一下,您可以使用 toString 私有方法定义一个类。然后,您不再平等地对待所有对象。例如,您将无法再安全地执行此操作:

    for (Object obj : collection) System.out.println(obj);

    【讨论】:

      【解决方案4】:

      这是 OOP 的基本原则:子类是父类的完整实例,因此必须提供与父类至少相同的接口。让受保护/公共的东西不那么显眼会违反这个想法;您可以使子类无法用作父类的实例。

      【讨论】:

        【解决方案5】:

        嗯,就您提到的具体情况而言,Java 究竟会如何处理呢?如果子类将公共/受保护的方法设为私有,那么当在子类的实例上调用该方法时 JVM 应该做什么?尊重私有并调用超类的实现?此外,当您突然说“没有人可以访问此方法,尽管合同最初是这样说的”时,您违反了超类指定的合同。

        【讨论】:

          【解决方案6】:

          举个例子

           class Person{
           public void display(){
                //some operation
              }
           }
          
          class Employee extends Person{
             private void display(){
                 //some operation
             }
           }
          

          典型的覆盖发生在以下情况

          Person p=new Employee();
          

          这里p是我们调用时类型为Person(super class)的对象引用 p.display()。由于访问修饰符的限制性更强,对象引用p 无法访问Employee 类型的子对象

          【讨论】:

            【解决方案7】:

            迟到了,但我想再补充一个与覆盖有关的问题:覆盖方法必须允许比被覆盖方法更少(或相同级别)的可抛出异常;甚至没有可扔的东西。

            里氏替换原理也可以解释:

            interface Actionable {
              void action() throws DislocationException;
            }
            
            public class Actor implements Actionable {
              @Override 
              public void action() throws DislocationException {
                 //....
              }
            } 
            
            public class Stuntman implements Actionable {
              @Override // this will cause compiler error
              public void action() throws DislocationException, DeathException {
                 //....
              }
            }
            
            // legacy code to use Actionable
            try {
               Actionable actor = new Actor(); // this cannot be replaced by a Stuntman, 
                                               // or it may break the try/catch block
               actor.action();
            } catch (DislocationException exc) {
               // Do something else
            }
            

            上面,被覆盖的方法承诺在最坏的情况下它会抛出 DislocationException,不再抛出(拍摄地点需要医生)。因此,覆盖方法不能通过添加更多 DeathException 来破坏它(或者必须使用救护车)

            我经常将最重要的规则称为“[可以]更多访问[级别],[但]更少例外”

            【讨论】:

              【解决方案8】:

              要重述已经说过的内容,它与 Java 如何编译成字节码有关,然后由 JVM 解释。当子类重写其父方法之一时,编译器使用引用类型来确定要使用这两种方法中的哪一种。然后 JVM 在运行时使用对象类型来确定应该真正使用哪种方法。

              在上面的例子中; Animal lion = new Lion(),当调用lion.getName() 时,编译器使用该方法的Animal 版本,JVM 替换它/可以用Lion 版本替换它,因为它“非常适合”。但是如果允许 Lion 对 getName() 的限制多于 Animal 限制的 getName(),则您可以绕过该限制,因为如果 Lion 对象具有 Animal 引用,编译器会将其视为不受限制。

              为了解决这个问题,java 使子进程使覆盖的方法比其覆盖的方法更受限制是非法的。

              【讨论】:

                猜你喜欢
                • 2023-04-09
                • 1970-01-01
                • 1970-01-01
                • 2021-11-29
                • 1970-01-01
                • 1970-01-01
                • 2019-09-17
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多