variable tipos reservadas privados para palabras otra los llamar herencia heredar heredan ejemplos derivada clase atributos java private

java - tipos - No se puede acceder a la variable privada desde la propia clase a través de la instancia de subclase



palabras reservadas para herencia en java (7)

class A { private int foo; void bar(B b) { b.foo = 42; } } class B extends A { }

Esto no se compila con el error:

A.java:3: error: foo has private access in A void bar(B b) { b.foo = 42; } ^ 1 error

Agregar un cast a la clase base lo hace funcionar.

void bar(B b) { ((A) b).foo = 42; }

¿Alguien puede indicarme una explicación sobre por qué el primer fragmento es ilegal? ¿Cuál es la razón por la que está prohibido? Esto es lo que dice el JLS :

De lo contrario, el miembro o el constructor se declara private , y el acceso está permitido si y solo si ocurre dentro del cuerpo de la clase de nivel superior (§7.6) que encierra la declaración del miembro o constructor.

Lo mejor que puedo decir, mi código cumple con esta redacción. Entonces, ¿esto es un error con el compilador de Java o mi interpretación de JLS es incorrecta?

(Nota: no estoy buscando soluciones, como hacer que la variable esté protected . Sé cómo solucionar esto).


¿No es esto para lo que es el modificador de acceso predeterminado?

Prueba esto :

public class blah{ static class A { int foo; void bar(B b) {b.foo=42;} } static class B extends A { } }

No puede acceder al miembro privado directamente desde un antepasado, eso es lo que significa privado. Ahora, ¿por qué funciona cuando lanzas? ¿Y eso significa que la documentación es incorrecta?

Le mencioné a un colega que la documentación de java puede ser errónea y él señala que en realidad está configurando el valor de foo dentro de la clase A. Así que todo es correcto. No puedes (porque es privado) acceder a foo desde un descendiente, por lo que debes lanzar. Y no puedes hacer eso fuera del cuerpo de A.

Creo que esta es la respuesta correcta.


El mensaje de error "tiene un acceso privado en A" es un error de Java durante mucho tiempo.

JDK 1.1:

JDK-4096353 : JLS 6.6.1: cuando se usan referencias de subclases para acceder a datos privados de superclases

contiene un fragmento de código que se ajusta exactamente a la pregunta uno

class X{ private static int i = 10; void f() { Y oy = new Y(); oy.i = 5; // Is this an error? Is i accessable through a reference to Y? } } class Y extends X {}

Intentaron arreglarlo y lleva a

JDK-4122297 : los mensajes de error de javac no son apropiados para un campo privado.

======TP1====== 1 class C extends S { 2 void f(){ 3 java.lang.System.out.println("foo"); 4 } 5 } 6 7 class S { 8 private int java; 9 } ====== % javac C.java C.java:3: Variable java in class S not accessible from class C. java.lang.System.out.println("foo"); ^ C.java:3: Attempt to reference field lang in a int. java.lang.System.out.println("foo"); ^ 2 errors ======

Pero según la especificación, java no se hereda en C y este programa debería compilar.

Se fijó en 1.2, pero vuelve a aparecer en 1.3.

JDK-4240480 : name00705.html: los miembros privados JLS6.3 no deben heredarse de las superclases

JDK-4249653 : el nuevo javac asume que los campos privados son heredados por una subclase

Y cuando vienen los genéricos.

JDK-6246814 : miembro privado de tipo variable accesible incorrectamente

JDK-7022052 : Error de compilador no válido en métodos privados y genéricos

Sin embargo, por el JLS este miembro simplemente no existe en el tipo heredado.

JLS 8.2. Miembros de la clase

Los miembros de una clase que se declaran privados no son heredados por las subclases de esa clase.

Entonces b.foo es ilegal porque la clase B no tiene un campo llamado foo . No es ninguna restricción, es un campo ausente en B

Java tiene una escritura fuerte y no podemos acceder a campos que no existen en B incluso si existen en la superclase A

El reparto (A) b es legal porque B es una subclase de A

A tiene un campo llamado foo y podemos acceder a este campo privado porque b(B b) es una función en la clase A incluso si b != this debido a

JLS 6.6.1. Determinando la accesibilidad

De lo contrario, si el miembro o el constructor se declara privado, entonces se permite el acceso si y solo si ocurre dentro del cuerpo de la clase de nivel superior (§7.6) que encierra la declaración del miembro o constructor.

Tambien si escribimos

class A { private int foo; void baz(A b) { b.foo = 42; } } class B extends A { } class T { void x() { B b = new B(); b.baz(b); } }

Se compilará porque Java infiere argumentos de tipo para llamadas polimórficas.

JLS 15.12.2.7. Inferir argumentos de tipo basados ​​en argumentos reales:

Una restricción de supertipo T:> X implica que la solución es uno de los supertipos de X. Dadas varias de estas restricciones en T, podemos intersecar los conjuntos de supertipos implicados por cada una de las restricciones, ya que el parámetro type debe ser un miembro de todos ellos. Luego podemos elegir el tipo más específico que se encuentra en la intersección.


Java es delicado al acceder a variables privadas a través de un tipo de referencia que no debería tener acceso a esa variable. Debe poder hacer esto legalmente escribiendo ((A) b).foo = 42 .


La especificación para expresiones de acceso a campos, capítulo 15.11 dice:

Si el identificador no nombra un campo miembro accesible en el tipo T, entonces el acceso al campo no está definido y se produce un error en tiempo de compilación.

Desde la perspectiva de la súper clase, mirando los tipos, diría que el miembro no es accesible , de ahí el error.

Creo que el caso que está presentando está más cerca de acceder a un miembro como un campo, que se muestra en el ejemplo 15.11-1-1.

class S { int x = 0; } class T extends S { int x = 1; } class Test1 { public static void main(String[] args) { T t = new T(); System.out.println("t.x=" + t.x + when("t", t)); S s = new S(); System.out.println("s.x=" + s.x + when("s", s)); s = t; System.out.println("s.x=" + s.x + when("s", s)); } static String when(String name, Object t) { return " when " + name + " holds a " + t.getClass() + " at run time."; } }

Sólo para responder a su pregunta:

Por favor explique qué tipo de código malo protege contra la restricción.

Por favor considere el siguiente fragmento.

public class X { private int a; public void bar(Z z) { z.a // not visible, but if was, what ''a'' // would you actually access at this point ''X'' or ''Z'' } } public class Z extends X { private int a; }


Me parece que la especificación es inconsistente. Como dice John, el cuerpo de los estados espec.

De lo contrario, el miembro o el constructor se declara privado, y el acceso está permitido si y solo si ocurre dentro del cuerpo de la clase de nivel superior (§7.6) que encierra la declaración del miembro o constructor.

y no hay mención de subclases. Así que la clase A debería compilar correctamente. Sin embargo, el ejemplo 6.6-5 estados

Se puede acceder a un miembro o constructor de clase privada solo dentro del cuerpo de la clase de nivel superior (§7.6) que encierra la declaración del miembro o constructor. No es heredado por subclases .

Esta segunda declaración es más débil (no solo si), pero trae subclases a la tabla. De acuerdo con esto, A no debe compilar.


No podemos heredar los campos o métodos private . Por lo tanto, en su código, la Clase B ignora por completo la variable foo , aunque esté accediendo desde su propia Clase A


No puede decir b.foo porque foo es privado y, por lo tanto, no se heredará, como resultado, la clase B no puede ver la variable foo y no sabe si existe una variable llamada foo , a menos que esté marcada como protegida (como usted dijo) o predeterminado (ya que están en el mismo paquete, supongo) o público.

Si desea usar foo sin usar una this.foo explícita como su segundo ejemplo, debe usar this.foo o simplemente foo que tiene this implícito. Como Javadocs especificó, la razón principal de this palabra clave es evitar que:

La razón más común para usar esta palabra clave es porque un campo está sombreado por un método o un parámetro constructor.

Cuando usó ((A) b) está emitiendo el tipo de referencia y el compilador lo verá como si estuviera usando un tipo de variable de referencia A , en otras palabras, algo como A a , y a.foo es completamente legal.

Un resumen ilustrado de la visibilidad y el acceso a las variables de instancia privada de la superclase: