Почему Java позволяет повысить видимость защищенных методов в дочернем классе?

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)

подкласса. Таким образом, ограничение не должно быть увеличено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... <strong>BooooOOMM ---> JVM Crashes</strong>.. because <code>meth</code> method is private in <code>class A</code>...

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

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

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

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

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

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

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

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

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.
      }
}
 25 сент. 2017 г., 21:01
Существует третья веская причина: подкласс всегда может сделать доступным другой открытый метод, который косвенно предоставляет защищенную функциональность. Поэтому любые попытки запретить его бессмысленны, поэтому Java позволяет вам улучшить видимость.
 30 окт. 2016 г., 17:34
Подумайте о методе клонирования. Он защищен, но вы должны сделать его защищенным или общедоступным.
 Narendra Pathai08 окт. 2012 г., 14:07
Спасибо, Пабло. Это то, что я искал, веский аргумент в пользу увеличения видимости.
 08 окт. 2012 г., 14:26
@NP_JavaGeek Если это был ответ, который вы искали, вы должны принять его (как объясненоhere)

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

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 Pathai08 окт. 2012 г., 13:43
Теперь я понял, спасибо. Но можете ли вы помочь мне с вопросом о методе шаблона? где мне нужно сделать некоторые важные вещи в базовом классе, и если два метода общедоступны, то я не могу сохранить контроль в базовом классе?
 23 февр. 2015 г., 20:47
Семантически, не было бы проблемы, позволяющей дочернему классу скрывать родительские элементы. Код, который получает итератор, может вызватьremove на нем, поскольку вызывающая сторона может передавать только итераторы, которые поддерживают этот метод; однако ничего не получается, позволяя коду, который получает строго типизированную ссылку на реализацию итератора неизменяемой коллекции, вызыватьremove на этом, так как эта операция не может работать. Опасность с позволениемprivate Переопределение состоит в том, что дочерний класс, возможно, намеревался создать приватную функцию, а не переопределять публичную.

Ваш ответ на вопрос