При переопределении метода, почему я могу увеличить доступ, но не уменьшить его? - PullRequest
59 голосов
/ 28 июля 2011

Почему Java указывает, что спецификатор доступа для переопределенного метода может разрешить больший, но не меньший доступ, чем переопределенный метод? Например, метод защищенного экземпляра в суперклассе можно сделать общедоступным, но не приватным, в подклассе.

Ответы [ 7 ]

65 голосов
/ 28 июля 2011

Это фундаментальный принцип в ООП: дочерний класс является полноценным экземпляром родительского класса и поэтому должен представлять как минимум тот же интерфейс , что и родительский класс. Делать защищенные / общественные вещи менее заметными нарушит эту идею; вы можете сделать дочерние классы непригодными в качестве экземпляров родительского класса.

33 голосов
/ 28 июля 2011

Представьте себе эти два класса:

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 . Поэтому невозможно сделать вещи менее заметными на подклассах, поскольку, получив ссылку на суперкласс, вы сможете получить к ней доступ.

9 голосов
/ 13 ноября 2013

Возьмите пример, приведенный ниже

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

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

Типичное переопределение происходит в следующем случае

Person p=new Employee();

Здесь p - ссылка на объект с типом Person (суперкласс), когда мы вызываем p.display () . Поскольку модификатор доступа является более строгим, ссылка на объект p не может получить доступ к дочернему объекту типа Employee

8 голосов
/ 28 июля 2011

Потому что это было бы странно:

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!
4 голосов
/ 30 апреля 2016

Поздно к вечеринке, но я хотел бы добавить еще одну проблему, связанную с переопределением: метод переопределения должен разрешать меньшее (или тот же уровень) выбрасываемое исключение, чем переопределенный метод; даже ничего не бросаемо вообще.

Принцип подстановки Лискова также может объяснить это:

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 (или необходима скорая помощь)

Я часто называю правило переопределения «[может быть] больше доступа [уровень], [но] меньше исключений»

0 голосов
/ 28 июля 2011

Ну, с точки зрения конкретного случая, который вы упомянули, как именно Java справится с этим?Если подкласс сделал открытый / защищенный метод частным, то что должна делать JVM, когда этот метод вызывается для экземпляра подкласса?Почитать приват и вызвать реализацию суперкласса?Кроме того, вы нарушаете контракт, указанный суперклассом, когда неожиданно говорите, что «никто не может получить доступ к этому методу, несмотря на то, что изначально было сказано в контракте».

0 голосов
/ 28 июля 2011

Поскольку подкласс является специализацией суперкласса, или, другими словами, это расширение суперкласса.

Представьте, например, метод toString.Все объекты Java имеют его, потому что он есть у класса Object.Представьте, что вы можете определить класс с помощью метода toString private.Вы больше не будете относиться ко всем объектам одинаково.Например, вы больше не сможете безопасно это сделать:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...