una - modificadores de acceso java




¿Puede un método de anulación tener un especificador de acceso diferente al de la clase base? (4)

Al reemplazar métodos, solo puede cambiar el modificador a uno más amplio , no al revés. Por ejemplo este código sería válido:

public abstract class A {

    protected void method();
}

public class B extends A {
    @Override
    public void method() { }
}

Sin embargo, si intenta reducir la visibilidad, obtendrá un error en tiempo de compilación:

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

public class B extends A {
    @Override
    private void method() {}
}

Para su caso, sugeriría hacer que C no implemente A , ya que la abstracción de A implica que hay un method() no privado method() :

public class C {
    private void method(){
      //TODO
    }
}

Otra opción es hacer la implementación de method() en C lanzando una RuntimeException:

public class C extends A {

    @Override
    public void method(){
        throw new UnsupportedOperationException("C doesn't support callbacks to method()");
    }
}

¿Qué modificador de acceso, en una clase abstracta, tengo que usar para un método, para que las subclases puedan decidir si debería ser público o no? ¿Es posible "anular" un modificador en Java o no?

public abstract class A {

    ??? void method();
}

public class B extends A {
    @Override
    public void method(){
        // TODO
    }
}

public class C extends B {
    @Override
    private void method(){
        // TODO
    }
}

Sé que habrá un problema con el enlace estático, si alguien llama:

// Will work
A foo = new B()
foo.method();

// Compiler ?
A foo = new C();
foo.method();

Pero tal vez hay otra manera. ¿Cómo puedo lograr eso?


Aquí hay una parte del contrato de @Override .

La respuesta es: no hay ninguna posibilidad de lograr lo que tienes.

El nivel de acceso no puede ser más restrictivo que el nivel de acceso del método anulado. Por ejemplo: si el método de superclase se declara público, el método de anulación en la subclase no puede ser privado ni protegido.

Este no es un problema relacionado con las clases abstract , sino con todas las clases y métodos.


Esto es imposible debido al polimorfismo. Considera lo siguiente. Tiene el método en la clase A con algún modificador de acceso que no es private . ¿Por qué no privado? Porque si era privado, entonces ninguna otra clase podría siquiera saber de su existencia. Por lo tanto, tiene que ser otra cosa, y esa otra cosa debe ser accesible desde algún lugar .

Ahora supongamos que pasas una instancia de la clase C a algún lugar . Pero lo subiste a A antemano, y así terminas teniendo este código en alguna parte :

void somewhereMethod(A instance) {
    instance.method(); // Ouch! Calling a private method on class C.
}

Un buen ejemplo de cómo se rompió esto es QSaveFile en Qt. A diferencia de Java, C ++ en realidad permite disminuir los privilegios de acceso. Así que hicieron eso, prohibiendo el método de close() . Lo que terminaron con una subclase de QIODevice que ya no es realmente un QIODevice . Si pasa un puntero a QSaveFile a algún método que acepte QIODevice* , aún pueden llamar a close() porque es público en QIODevice . " QSaveFile::close() " esto haciendo que QSaveFile::close() (que es privado) llame a abort() , así que si haces algo así, tu programa se bloquea de inmediato. No es una "solución" muy agradable, pero no hay una mejor. Y es solo un ejemplo de mal diseño OO. Es por eso que Java no lo permite.

Editar

No es que me haya perdido que tu clase sea abstracta, pero también me di cuenta de que B extends C , no A De esta manera lo que quieres hacer es completamente imposible. Si el método es public en B, también lo será en todas las subclases. Lo único que puede hacer es documentar que no se debe llamar y, posiblemente, anularlo para lanzar la UnsupportedOperationException . Pero eso llevaría a los mismos problemas que con QSaveFile . Recuerde que los usuarios de su clase ni siquiera saben que es una instancia de C por lo que ni siquiera tendrán la oportunidad de leer su documentación.

En general, es solo una muy mala idea. Tal vez debería hacer otra pregunta sobre el problema exacto que está tratando de resolver con esta jerarquía, y quizás obtenga algunos consejos decentes sobre cómo hacerlo correctamente.


Lo que estás pidiendo no es posible por muy buenas razones.

El principio de sustitución de Liskov básicamente dice: una clase S es una subclase de otra clase T solo entonces, cuando puedes reemplazar cualquier aparición de algún "objeto T" con algún "objeto S", sin darte cuenta.

Si permites que S esté reduciendo un método público a privado, entonces ya no puedes hacerlo. Porque de repente, ese método que podría llamarse mientras se usa algo de T ... ya no está disponible para ser llamado en S.

Larga historia corta: la herencia no es algo que simplemente se cae del cielo. Es una propiedad de las clases de la que usted, como programador, es responsable. En otras palabras: ¡la herencia significa más que simplemente escribir "clase S extiende T" en su código fuente!





modifiers