java - modificadores - pildorasinformaticas interfaces
modificadores de acceso de Java y métodos de anulación (7)
Bueno, en términos del caso específico que mencionaste, ¿cómo manejaría eso exactamente Java? Si la subclase hizo privado un método público / protegido, ¿qué debería hacer la JVM cuando se invoca ese método en una instancia de la subclase? ¿Honrar lo privado e invocar la implementación de la superclase? Además, está incumpliendo el contrato especificado por la superclase cuando de repente dice "nadie puede acceder a este método, a pesar de lo que inicialmente decía el contrato".
¿Por qué Java especifica que el especificador de acceso para un método de anulación puede permitir más, pero no menos, acceso que el método reemplazado? Por ejemplo, un método de instancia protegida en la superclase puede hacerse público, pero no privado, en la subclase.
Debido a que una subclase es una especialización de la superclase, o en otras palabras, es una extensión de la superclase.
Imagine por ejemplo el método toString. Todos los objetos Java lo tienen porque la clase Object lo tiene. Imagine que puede definir una clase con el método toString private. Entonces ya no tratarás a todos los objetos por igual. Por ejemplo, ya no podría hacerlo de manera segura:
for (Object obj : collection) System.out.println(obj);
Es un principio fundamental en OOP: la clase hija es una instancia completamente desarrollada de la clase principal y, por lo tanto, debe presentar al menos la misma interfaz que la clase principal. Hacer las cosas protegidas / públicas menos visibles violaría esta idea; podría hacer que las clases secundarias no se puedan usar como instancias de la clase principal.
Imagina estas dos clases:
public class Animal {
public String getName() { return this.name; }
}
public class Lion extends Animal {
private String getName() { return this.name; }
}
Podría escribir este código:
Animal lion = new Lion();
System.out.println( lion.getName() );
Y tendría que ser válido, ya que en Animal el método getName () es público, incluso si se hizo privado en Lion . Por lo tanto, no es posible hacer que las cosas sean menos visibles en las subclases, ya que una vez que tenga una referencia de superclase, podrá acceder a esta información.
Porque sería extraño:
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!
Tarde en la fiesta, pero me gustaría agregar una preocupación más relacionada con la anulación: El método de anulación debe permitir menos (o el mismo nivel de) excepción susceptible de lanzamiento que el método anulado; incluso nada arrojable en absoluto.
El principio de sustitución de Liskov puede explicar eso también:
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
}
Arriba, el método anulado asumió el compromiso de que en el peor de los casos arrojaría la DislocationException, no más (se requiere un médico en el lugar de la filmación). Entonces, el método predominante no debe romper eso, al agregar más DeathException (o una ambulancia es imprescindible)
A menudo llamo a la regla primordial "[puede ser] más acceso [nivel], [pero] menos excepción"
Tome un ejemplo dado a continuación
class Person{
public void display(){
//some operation
}
}
class Employee extends Person{
private void display(){
//some operation
}
}
La anulación típica ocurre en el siguiente caso
Person p=new Employee();
Aquí p
es la referencia del objeto con el tipo Persona ( superclase ) cuando llamamos a p.display () . Como el modificador de acceso es más restrictivo, la referencia de objeto p
no puede acceder al objeto hijo de tipo Empleado