¿Por qué Java permite boost la visibilidad de los métodos protegidos en la clase infantil?

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

¿Por qué no podemos reducir la visibilidad pero podemos boostla?

También necesito implementar el patrón de Plantilla en el que los métodos públicos visibles solo pueden ser de clase base.

Ejemplo:

 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 } } 

Ahora, si java permite boost la visibilidad, ¿hay dos métodos visibles públicamente?

Sé que la interfaz es una solución, pero ¿hay alguna otra salida?

Por qué la disminución de la visibilidad no está permitida ya se explica en otras respuestas (rompería el contrato de la clase principal).

Pero, ¿por qué se permite boost la visibilidad de un método? Primero, no rompería ningún contrato, por lo que no hay razón para no permitirlo. A veces puede ser útil, cuando tiene sentido en la clase infantil que un método no esté protegido.

En segundo lugar, no permitirlo podría tener el efecto secundario de hacer imposible a veces extender una clase e implementar una interfaz al mismo tiempo:

 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. } 

Sobre su segunda pregunta, no puede hacer nada al respecto. Debes confiar en que la persona que implementa la clase infantil no haga nada que rompa tu implementación. Incluso si java no permitiera boost la visibilidad, eso aún no solucionaría su problema, porque se podría crear un método público con un nombre diferente que invoque el método abstracto:

 class Child extends Base{ @Override protected void a(){ } public void a2() { a(); //This would have the same problems that allowing to increase the visibility. } } 

Si la clase base hace una promesa con respecto a la visibilidad, entonces la subclase no puede romper esa promesa y aún así cumplir con el principio de sustitución de Liskov. No puede usar una subclase en ninguna situación donde el método prometido quede expuesto si esa promesa se rompe.

La subclase clase base IS-A. Si la clase base expone un método, también lo debe hacer la subclase.

No hay salida en Java o C ++. Supongo que lo mismo es cierto en C #.

¿Por qué no podemos reducir la visibilidad pero podemos boostla?

Supongamos que sería posible reducir la visibilidad. Luego mira el siguiente código:

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

Supongamos que tendría otra clase, en otro paquete, donde utiliza estas clases:

 Super a = new Sub(); // Should this be allowed or not? a.method(); 

Para verificar si una llamada a método está permitida o no, el comstackdor observa el tipo de la variable a la que lo llama. El tipo de la variable a es Super . Pero el objeto real al que a refiere es un Sub , y allí el método está protected , por lo que diría que no debería permitirse llamar al método desde una clase no relacionada fuera del paquete. Para resolver esta extraña situación, está prohibido hacer que los métodos anulados sean menos visibles.

Tenga en cuenta que al revés (hacer que un método sea más visible) no conduce al mismo problema.

Dado que Java permite que la referencia de la clase Súper apunte a un objeto de clase secundaria … Por lo tanto, la restricción no se debe boost desde compile-time de compile-time de runtime .

Veamos esto a través de un ejemplo:

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

Ahora, crea un objeto de clase A y asígnele la referencia de clase B Veamos cómo:

 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.. 

Ahora, dado que el compiler solo verifica el tipo de la variable de referencia , y verifica la visibilidad de los métodos en esa clase (clase B) , y no verifica a qué tipo de objeto se refiere el obj de referencia. Por lo tanto, no es preocupado por eso … JVM en tiempo de ejecución debe resolver el método apropiado …

Pero en tiempo de ejecución , JVM intentará invocar el método meth de la clase A como objeto de clase A. Pero, ahora qué sucede … BooooOOMM —> JVM se cuelga … porque el método meth es privado en la class A ..

Es por eso que no se permite que la visibilidad disminuya.