Si los atributos privados no se heredan, por que están presentes al crear una instancia de la subclase?
Ahi les va esta pregunta.
Es bien sabido ( y si no lo sabían ) que los miembros privados de una clase no se heredan.
Entonces por que cuando creamos una instancia de una subclase, los miembros privado están ahí? Me queda claro que la respuesta no es "por que fueron heredados", pero tampoco puedo obtener una explicación convincente.
-
class A {
-
private int i;
-
}
-
class B extends A {
-
}
-
class UseIt {
-
new B();
-
}
-
}
Si pudiéramos ver el objeto creado en la linea 8, veríamos que la variable i definida en la clase A, está presente.
Alguien puede explicar por que sin decir "por que sí se heredan" ? :)
Pregunta original Does subclasses inherit private fields? [ en StackOverflow - en inglés -]
Mi no tan convincente respuesta
Saludos.
- Inicie sesión o regístrese para enviar comentarios
no
si pudiéramos ver el objeto creado en la linea 8
Si mi abuelita tuviera ruedas, sería bicicleta.
Cómo podríamos ver el objeto en la linea 8? Para cualquier efecto práctico, la variable i no se hereda. No es accesible desde la clase B. Si le pones a la clase A un
public int getI() { return i; }
entonces puedes invocar ese método y así obtener el valor que tenga la variablei
, y si le pones unpublic void setI(int value) { i = value; }
en A, puedes modificar el valor de la variable, incluso desde B, pero no tienes acceso directo a la variable desde la clase B.Haciendo reflection sobre B puedes encontrar la variable
i
pero si la intentas leer se arrojará una excepción. No es accesible.Ahhh que con el escepticismo
Ahhh que con el escepticismo caray.
Estoy dando por hecho que el valor está ahí, pero nunca dije que fuera accesible. De hecho estoy afirmando que NO se hereda, pero no logro explicar por que SI está presente. El como obtenerla no es lo importante aquí, sino el por que está presente.
De todas formas ( nomás para permitir que la pregunta pueda ser contestada ) aquí está la prueba de que el valor si esta presente usando Java VisualVM que viene en todas las distribuciones de
SunOracle de JavaAhora, confirmando con las imagenes que el valor si está ( La foto de la abuelita-bicicleta queda pendiente o_O )
¿Por que está la variable i presente, si no es heredada?
por acceso
Está presente en la subclase, porque si la superclase tiene métodos que la utilicen, al invocarse con el contexto de la subclase necesitan ver esa variable, pero solamente como métodos de la superclase la puedan accesar. Una optimización de runtime nada mas.
Claro que los atributos se "heredan"
La visibilidad en los atributos no afecta la herencia de los mismos en las clases derivadas. Todo atributo codificado en cualquier lugar de la jerarquía de clases, es heredado por las clases derivadas y forma parte del estado de los objetos de esas clases derivadas, aunque los métodos de esas clases no tengan acceso a los atributos privados de sus clases bases.
Tampoco se trata de un problema de optimización de runtime. Se trata en esencia de usar la herencia correctamente como una de las técnicas posibles para describir de manera incremental un concepto usando el principio de generalización/ (especialización y/o extensión).
Al codificar atributos privados en una clase, estamos asumiendo que todo lo que tenga que ver con administrar el estado de los objetos que está representado por esos atributos, puede codificarse en esa clase y entonces conviene "ocultarlos" al resto de las clases que están más abajo en la jerarquía de herencia. Es una decisión nada trivial y que con frecuencia sucede que necesitamos cambiar esa visibilidad.
Algunos lo resuelven con getters y setters protegidos para que las clases derivadas puedan entonces manipular esos atributos, pero se abusa mucho de eso, lo que en ocasiones resulta en jerarquías de herencia mal diseñadas.
¿Mal definido?
¿Entonces está mal la definición? El tutorial de
SunOracle dice al respecto:Ese "does not inherit" en realidad no es tal, las variables sí se heredan pero no es posible accederlas directamente.
¿Es correcto?
¿?
Alguien responda esto. Tengo la misma duda que benek.
sí
es correcto.
private int priv;
public void setPriv(int value) { priv=value; }
public int getPriv() { return priv; }
}
public class Hijo extends Padre {
public void noCompila() {
priv=0;
}
public void siCompila() {
setPriv(0);
}
}
La clase Padre define la variable privada
priv
. Esa variable no se hereda a la clase Hijo. Pero los accesores depriv
son públicos, por lo que Hijo sí los puede invocar. El métodosiCompila
invoca al métodosetPriv
, que al no estar sobreescrito en la subclase, se invoca directamente en la clase Padre y se modifica el valor depriv
(digamos que las instancias de Hijo tienen su propiopriv
pero no lo pueden ver directamente).Agradecida
Sé que hace tiempo de este post, pero agradezco a todos su aportación, ha sido muy constructivo para mí y ha resuelto mis dudas.
Gracias.