Вопрос по design-patterns, java – Почему Java позволяет повысить видимость защищенных методов в дочернем классе?

13
abstract class Base{
      protected abstract void a();
}

class Child extends Base{
      @Override
      public void a(){
          //why is this valid
      }
}

Почему мы не можем уменьшить видимость, но можем ее увеличить?

Также мне нужно реализоватьTemplate pattern в котором видимые публичные методы могут быть только базового класса.

Пример:

abstract class Base{
      public void callA(){
      //do some important stuff
      a();
      }

      protected abstract void a();
}

class Child extends Base{
      @Override
      public void a(){
          //why is this valid
      }
}

Теперь, если Java позволяет увеличить видимость, то есть два метода, видимых публично ??

Я знаю, что интерфейс - это одно из решений, но есть ли другой выход ???

Ваш Ответ

4   ответа
0

подкласса. Таким образом, ограничение не должно быть увеличеноcompile-time вruntime..

Давайте рассмотрим это на примере:

public class B {
    public void meth() {

    }
}

class A extends B {
    private void meth() {  // Decrease visibility.

    }
}

Теперь вы создаете объект классаA и назначьте ему ссылку классаB.. Lets see how: -

B obj = new A();  // Perfectly valid.

obj.meth();  // Compiler only checks the reference class..
             // Since meth() method is public in class B, Compiler allows this..
             // But at runtime JVM - Crashes..

Теперь, так какcompiler только проверяетtype of the reference variableи проверьте видимость методов в этом классе(class B), и этоdoesn't check what kind of object делаетreference obj ссылается на .. Итак, его это не беспокоит .. Это оставлено JVM во время выполнения для разрешения подходящего метода ..

Ноat runtimeJVM на самом деле будет пытатьсяinvoke the meth метод классаA as object is of class A.. But, now what happens... BooooOOMM ---> JVM Crashes.. because meth method is private in class A...

Вот почему видимость не может быть уменьшена.

22

уже объяснено в других ответах (это нарушит контракт родительского класса).

Но почему разрешено увеличивать видимость метода? Во-первых, это не нарушило бы ни один контракт, поэтому нет никаких причин, чтобы этого не допустить. Иногда это может быть полезно, когда в дочернем классе имеет смысл не защищать метод.

Во-вторых, недопущение этого может иметь побочный эффект: иногда невозможно расширить класс и реализовать интерфейс:

interface Interface1 {
   public void method();
}

public class Parent {
   protected abstract void method();
}

public class Child extends Parent implements Interface1 {
   @Override
   public void method() {
   }
   //This would be impossible if the visibility of method() in class Parent could not be increased.
}

Что касается вашего второго вопроса, вы ничего не можете с этим поделать. Вы должны верить, что человек, который реализует дочерний класс, не делает ничего, что нарушает вашу реализацию. Даже если java не позволит увеличить видимость, это все равно не решит вашу проблему, потому что можно создать открытый метод с другим именем, который вызывает абстрактный метод:

class Child extends Base{
      @Override
      protected void a(){

      }

      public void a2() {
           a(); //This would have the same problems that allowing to increase the visibility.
      }
}
Подумайте о методе клонирования. Он защищен, но вы должны сделать его защищенным или общедоступным.
@NP_JavaGeek Если это был ответ, который вы искали, вы должны принять его (как объясненоhere)
Существует третья веская причина: подкласс всегда может сделать доступным другой открытый метод, который косвенно предоставляет защищенную функциональность. Поэтому любые попытки запретить его бессмысленны, поэтому Java позволяет вам улучшить видимость.
Спасибо, Пабло. Это то, что я искал, веский аргумент в пользу увеличения видимости. Narendra Pathai
3

Предположим, что можно было бы уменьшить видимость. Затем посмотрите на следующий код:

class Super {
    public void method() {
        // ...
    }
}

class Sub extends Super {
    @Override
    protected void method() {
        // ...
    }
}

Предположим, что у вас был бы другой класс, в другом пакете, где вы используете эти классы:

Super a = new Sub();

// Should this be allowed or not?
a.method();

Чтобы проверить, разрешен ли вызов метода или нет, компилятор проверяет тип переменной, для которой он вызывается. Тип переменнойa являетсяSuper, Но фактический объект, которыйa относится к этоSubи там методprotected, так что вы бы сказали, что нельзя вызывать метод из несвязанного класса вне пакета. Чтобы разрешить эту странную ситуацию, было запрещено делать переопределенные методы менее заметными.

Обратите внимание, что обратное (делая метод более заметным) не приводит к той же проблеме.

Теперь я понял, спасибо. Но можете ли вы помочь мне с вопросом о методе шаблона? где мне нужно сделать некоторые важные вещи в базовом классе, и если два метода общедоступны, то я не могу сохранить контроль в базовом классе? Narendra Pathai
Семантически, не было бы проблемы, позволяющей дочернему классу скрывать родительские элементы. Код, который получает итератор, может вызватьremove на нем, поскольку вызывающая сторона может передавать только итераторы, которые поддерживают этот метод; однако ничего не получается, позволяя коду, который получает строго типизированную ссылку на реализацию итератора неизменяемой коллекции, вызыватьremove на этом, так как эта операция не может работать. Опасность с позволениемprivate Переопределение состоит в том, что дочерний класс, возможно, намеревался создать приватную функцию, а не переопределять публичную.
12

то подкласс не может нарушить это обещание и все еще удовлетворяет принципу замены Лискова. Вы не можете использовать подкласс в любой ситуации, когда обещанный метод доступен, если это обещание нарушено.

Подкласс IS-A базовый класс. Если базовый класс предоставляет метод, то и подкласс должен.

Нет выхода в Java или C ++. Я полагаю, что то же самое верно для C #.

Один вопросительный знак на вопрос подойдет. Я думаю, что "нет" должно быть достаточно легко понять. Вы не можете сделать метод менее видимым в дочернем элементе, чем в родительском. Пусть компилятор скажет вам ответ. Это лучше, чем приходить сюда и спрашивать.
простите за вопросительные знаки. но вы можете помочь мне со вторым примером, который я написал. Narendra Pathai
Я не получил ответ полностью ?? Итак, вы говорите, что я не могу ограничить дочерний класс от увеличения видимости каким-либо образом? Narendra Pathai
да, теперь я понимаю этот принцип. но что я могу сделать, чтобы заставить этот метод базового класса выполняться, что является моей реальной проблемой! см. мой второй пример. Narendra Pathai
В чем проблема? Ребенок может выбрать методmore видимый, чем его родитель, но он не может сделать этоless видимый. Это все еще удовлетворяет Лискова; это все еще ЕСТЬ-родитель; Вы можете вызвать более видимый дочерний метод a () в любом контексте, где вызывается родительский метод a ().

Похожие вопросы