Tengo una clase que tiene un método cuyo especificador de acceso por defecto es public. Ahora, me gustaría extender esta clase en una subclase y quiero invalidar este método para tener acceso especificador de «privado». Al compilar este código, estoy recibiendo un error de compilación:

«intentar asignar más débil de los privilegios de acceso».

Podría alguien por favor que me explique lo que está mal con la asignación de más débil de los privilegios de una subclase?

Aquí está el código que causó el error de compilación:

class Superclass 
{
    void foo() 
    {
        System.out.println("Superclass.foo");
    }
}

class Subclass extends Superclass 
{
    private void foo() 
    {
        System.out.println("Subclass.foo");
    }
}
  • Interesante pregunta! Este mismo caso está permitido en C++.
  • «Tengo una clase que tiene un método cuyo especificador de acceso por defecto es público». En realidad el valor predeterminado especificador de acceso no es pública. Si usted hizo no se menciona ningún tipo específico de especificador de acceso, a continuación, es «por defecto»:).
  • Y lo que sucede en C++ cuando accedes a un objeto a través de una superclase con tipo variable? El compilador seguramente le permite a través de… ¿error en tiempo de ejecución?
  • Yo estaba tratando de desentrañar que la declaración de quamrana 🙂
  • En el caso de C++ y el ejemplo de arriba (digamos público en la clase de base privada en la clase derivada) acceso sólo depende del puntero que tiene a mano. No hay errores de tiempo de ejecución, sólo errores en tiempo de compilación (acceso privado método desde fuera de la clase).
InformationsquelleAutor syam | 2013-07-07

7 Comentarios

  1. 27

    La respuesta corta es que no es permitido porque se rompería el tipo de sustituibilidad; véase también el Liskov Substititution Principio (LSP).

    El punto es que el polimorfismo en Java y otros lenguajes de programación) se basa en ser capaces de tratar a una instancia de una subclase como si fue una instancia de la superclase. Pero si el método está restringido en la subclase, se encuentra que el compilador no puede determinar si las reglas de acceso permiten un método que se llama …

    Por ejemplo, supongamos que su código de ejemplo fue legal:

    //Assume this code is in some other class ...
    
    SuperClass s1 = new SuperClass();
    
    s1.foo();                          //OK!
    
    SuperClass s2 = new Subclass();
    
    s2.foo();                          //What happens now?
    
    SuperClass s3 = OtherClass.someMethod();
    
    s3.foo();                          //What happens now?

    Si la base de la decisión sobre si s2.foo() está permitido en el tipo declarado de s2, a continuación, permitir que una llamada a un private método de fuera de la abstracción límite de Subclass.

    Si la base de la decisión sobre el tipo real del objeto que s2 se refiere, no se puede hacer la comprobación de acceso de forma estática. El s3 caso hace esto aún más claro. El compilador no tiene absolutamente ninguna manera de saber lo que el tipo real del objeto devuelto por someMethod será.

    Comprobaciones de acceso que podría resultar en excepciones de tiempo de ejecución sería una fuente importante de errores en la aplicación de Java. El lenguaje de restricción en discusión aquí, evita este desagradable problema.

  2. 8

    No puede restringir el acceso porque ya ha permitido un mayor acceso en la clase super. por ejemplo,

    SuperClass sc = new SubClass();
    sc.foo(); //is package local, not private.

    El acceso de sc está determinado por el tipo de la referencia sc no lo que las referencias porque es imposible que el compilador sepa en todos los casos lo que el tipo de objeto en tiempo de ejecución. Para que esto sea una suposición segura la sub-clase deben cumplir con el contrato otorgado por el padre, madre o no ser válido subclase. Esto no es diferente a la de los padres diciendo que un método es aplicado, pero la sub clase diciendo que no es (o no es accesible)

    Usted podría trabajar alrededor de esto diciendo que sólo se puede acceder a la sub-clase de método a través de los padres, no directamente. El problema con esto es que no se sabe cuando un padre podría agregar un método y cuando usted hace un método private hacer esto porque quiero que sea privado, y que no son accesibles de otro modo.

    Por CIERTO, Usted todavía puede tener acceso a un método privado a través de la reflexión, que tiene el efecto secundario que causa todo tipo de problemas para la JVM. por ejemplo, se tiene que mantener en privado los métodos a pesar de que podría determinar que no hay forma en que puede ser llamado normalmente.

    En pocas palabras, usted necesita el código de lo que significa lo que dice, y no tener una personalidad dividida. Es el paquete de local o es privado no algo de suerte en el entre, pero no realmente bien. Esto no es un problema de la otra manera. es decir, si el sub clase es pública. Simplemente significa que el sub-clase se puede utilizar en más lugares de los que el padre, como se puede implementar más métodos.

    • Sí, pero ¿por qué tiene que ser (es lo que él está pidiendo a)?
  3. 6

    Si se permitiera, sería una puerta trasera a través del cual usted puede llamar a métodos que no debe ser accesible.

    Digamos que esto está permitido

    class Super {  
        public void method() {  
            System.out.println("Super");  
        }  
    }
    
    
    class Sub extends Super {  
        //This is not allowed, but suppose it was allowed  
        protected void method() {  
            System.out.println("Sub");  
        }  
    }
    
    //In another class, in another package:  
    Super obj = new Sub();  
    obj.method();

    obj.method sería posible, porque method() es public en la clase Super. Pero no debe ser permitido,
    porque obj es en realidad hace referencia a una instancia de África, y en esa clase, el método está protegido!

    Para restringir una llamada a un método en la clase Sub que no debe ser accesible desde el exterior, esta restricción se pone.

  4. 1

    Estrechando el modificador de acceso de un super clase de método no es válida anular porque es romper la super-clase de contrato y invalida el principio de sustitución es decir, un sub-clase de objeto ES UN super clase de objeto así.

    public void doSomething(SuperClass sc) {
      sc.publicMethodInSuperClass();
    }
    
    doSomething(new SubClass()); //would break

    Si esto se permite, el anterior código de cliente que se iba a romper debido a su Subclase no tiene ese método público.

    Referencia:

    Principio de sustitución de Liskov

  5. 0

    Aparte de los evidentes problemas con el uso de tales construcciones(como señaló Peter Lawrey en su respuesta), leer sobre la teoría detrás de ella así: LSP, lo que significa que debe ser capaz de sustituir el principal tipo con su subclase.

    • +1 LSP es la razón. Buen enlace.
  6. 0

    Creo que la respuesta corta es que el compilador escritores han de establecer las reglas para trabajar de esta manera. LSP tiene nada que ver con el problema en cuestión.

    La única razón que se me ocurre para tener esta restricción es que cuando una subclase se deriva de una interfaz, como un cliente programador, espera ser capaz de llamar a todos los de la accesibilidad a los métodos de la interfaz a partir de una referencia a la clase derivada.

    Suponga que usted podría escribir el código que el OP lo ha demostrado. Si usted tiene un de referencia de la clase derivada debe ser capaz de llamar a cualquiera de los miembros públicos de la clase derivada (a pesar de que no hay nada en este caso). Sin embargo, pasar la referencia como parámetro a un método que toma una referencia a la clase base y el método de espera para llamar a cualquier público o paquete de método, que es foo. Este es el LSP que otros colaboradores están buscando!

    C++ ejemplo:

    class Superclass{
    public:
    virtual void foo(){ cout << "Superclass.foo" << endl; }
    };
    
    class Subclass: public Superclass{
    virtual void foo(){ cout << "Subclass.foo" << endl; }
    };
    
    int main(){
    Superclass s1;
    s1.foo() //Prints Superclass.foo
    
    Subclass s2;
    //s2.foo();  //Error, would not compile
    
    Superclass& s1a=s2; //Reference to Superclass 'pointing' to Subclass
    
    s1a.foo(); //Compiles OK, Prints Subclass.foo()
    }
    • «La única razón que se me ocurre para tener esta restricción es que cuando una subclase se deriva de una interfaz, como un cliente programador, espera ser capaz de llamar a todos los de la accesibilidad a los métodos de la interfaz a partir de una referencia a la clase derivada.» – Eso es básicamente LSP. Porque, si el cliente programador no se puede hacer eso, entonces la subclase no puede ser sustituida por la de los padres de clase!
    • No no. LSP se refiere a la perspectiva del cliente, donde sólo ellos saben acerca de la clase base y esperar que la clase base para trabajar de una determinada manera. Cuando el suministro de una clase derivada para el cliente, ya que su lenguaje lo permite, entonces la clase derivada debe comportarse de la misma manera, tal que la función de cliente todavía funciona.
    • Creo que usted está interpretando el LSP demasiado estrecho. El Liskov & Ala definición es esta: «Subtipo Requisito: Dejar que ϕ ( x ) es una propiedad comprobable acerca de los objetos x de tipo T. Entonces ϕ ( y ) debe ser cierto para los objetos y de tipo S, donde S es un subtipo de T». En este caso, ϕ es tener un método accesible foo. Esta es una propiedad de SuperClass que los clientes dependen de, y por lo tanto también debe ser una propiedad de SubClass … o de lo contrario un ejemplo de esto último es que no sustituibles por una instancia de la antigua. Consulte en.wikipedia.org/wiki/Liskov_substitution_principle
  7. 0

    En la dinámica del método de envío, llame al método reemplazado se resuelve en tiempo de ejecución en lugar de tiempo de compilación. Se basa en el objeto que se hace referencia en el momento de la llamada…

    Supongamos ahora más débil de privilegios de acceso se permitió y escribimos la siguiente instrucción en el código de otra clase:

    Superclass ref=new Subclass();
    ref.foo()

    Ahora durante el tiempo de ejecución, cuando java viene a través de la declaración de ref.foo(), se tendrá que llamar a foo() de Subclass…pero foo() método de la subclase está declarada como privada en el código y privada no puede ser llamado fuera de su propia clase..así que ahora hay un conflicto y que el resultado sería excepción en tiempo de ejecución…

Dejar respuesta

Please enter your comment!
Please enter your name here