privados - herencia simple en java
¿Las subclases heredan campos privados? (17)
Esta es una pregunta de entrevista.
¿Las subclases heredan campos privados?
Respondí "No", porque no podemos acceder a ellos usando la "forma normal de OOP". Pero el entrevistador piensa que se heredan, porque podemos acceder a dichos campos de manera indirecta o mediante la reflexión y aún existen en el objeto.
Después de regresar, encontré la siguiente cita en el javadoc :
Miembros privados en una Superclase
Una subclase no hereda a los miembros privados de su clase padre.
¿Conoces algún argumento a favor de la opinión del entrevistador?
Sí
Es importante darse cuenta de que si bien hay dos clases, solo hay un objeto.
Entonces, sí, claro que heredó los campos privados. Son, presumiblemente, esenciales para la funcionalidad adecuada del objeto, y si bien un objeto de la clase principal no es un objeto de la clase derivada, una instancia de la clase derivada es, en su mayoría, definitivamente una instancia de la clase primaria. No podría ser eso sin todos los campos.
No, no puedes acceder directamente a ellos. Sí, se heredan. Tienen que ser
¡Es una buena pregunta!
Actualizar:
Err, "No"
Bueno, supongo que todos aprendimos algo. Dado que JLS originó la redacción exacta "no heredada", es correcto responder "no" . Como la subclase no puede acceder o modificar los campos privados, en otras palabras, no se heredan. Pero realmente solo hay un objeto, realmente contiene los campos privados, y por lo tanto, si alguien toma el JLS y el tutorial de forma incorrecta, será bastante difícil entender la POO, los objetos Java y lo que realmente está sucediendo.
Actualizar para actualizar:
La controversia aquí involucra una ambigüedad fundamental: ¿qué se está discutiendo exactamente? El objeto? ¿O estamos hablando en algún sentido sobre la clase en sí? Se permite una gran cantidad de latitud cuando se describe la clase en oposición al objeto. Así que la subclase no hereda los campos privados, pero un objeto que es una instancia de la subclase ciertamente contiene los campos privados.
Bueno, mi respuesta a la pregunta del entrevistador es: los miembros privados no se heredan en subclases, pero son accesibles a la subclase o al objeto de la subclase solo a través de métodos de captador o definidor públicos o cualquier método apropiado de la clase original. La práctica habitual es mantener a los miembros privados y acceder a ellos utilizando métodos de obtención y establecimiento que son públicos. Entonces, ¿cuál es el punto de solo heredar los métodos getter y setter cuando el miembro privado con el que tratan no está disponible para el objeto? Aquí ''heredado'' simplemente significa que está disponible directamente en la subclase para jugar con los métodos recién introducidos en la subclase.
Guarde el archivo siguiente como ParentClass.java y pruébelo usted mismo ->
public class ParentClass {
private int x;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
}
class SubClass extends ParentClass {
private int y;
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public void setXofParent(int x) {
setX(x);
}
}
class Main {
public static void main(String[] args) {
SubClass s = new SubClass();
s.setX(10);
s.setY(12);
System.out.println("X is :"+s.getX());
System.out.println("Y is :"+s.getY());
s.setXofParent(13);
System.out.println("Now X is :"+s.getX());
}
}
Output:
X is :10
Y is :12
Now X is :13
Si intentamos usar la variable privada x de ParentClass en el método de SubClass, no será directamente accesible para ninguna modificación (significa que no se hereda). Pero x se puede modificar en la SubClase mediante el método setX () de la clase original como se hace en el método setXofParent () O se puede modificar usando el objeto ChildClass usando el método setX () o el método setXofParent () que finalmente llama setX (). Así que aquí setX () y getX () son una especie de puertas para el miembro privado x de una ParentClass.
Otro ejemplo simple es que la superclase del reloj tiene horas y minutos como miembros privados y métodos adecuados de obtención y configuración como público. Luego viene DigitalClock como una subclase de Reloj. Aquí, si el objeto de DigitalClock no contiene horas y minutos, entonces las cosas se complican.
Creo que la respuesta depende totalmente de la pregunta que se ha formulado. Quiero decir, si la pregunta es
¿Podemos acceder directamente al campo privado de la superclase desde su subclase?
Entonces la respuesta es No , si revisamos los detalles del especificador de acceso , se menciona que solo se puede acceder a los miembros privados dentro de la propia clase.
Pero, si la pregunta es
¿Podemos acceder al campo privado de la superclase desde su subclase?
Lo que significa, no importa, qué hará para acceder al miembro privado. En ese caso, podemos hacer un método público en la súper clase y usted puede acceder al miembro privado. Entonces, en este caso, está creando una interfaz / puente para acceder al miembro privado.
Otros lenguajes OOP, como C ++, tienen el concepto de friend function
, mediante el cual podemos acceder al miembro privado de otra clase.
Demostraré el concepto con código. Subclases REALMENTE heredan las variables privadas de la súper clase. El único problema es que no son accesibles para los objetos secundarios a menos que proporcione captadores y definidores públicos para las variables privadas en la superclase.
Considere dos clases en el paquete de volcado. El niño se extiende padre.
Si recuerdo correctamente, un objeto hijo en memoria consta de dos regiones. Una es solo la parte principal y la otra es solo la parte secundaria. Un niño puede acceder a la sección privada en el código de su padre solo a través de un método público en el padre.
Piénsalo de esta manera. El padre de Borat, Boltok, tiene una caja fuerte que contiene $ 100,000. Él no quiere compartir su variable "privada" segura. Por lo tanto, no proporciona una clave para la caja fuerte. Borat hereda la caja fuerte. Pero, ¿de qué sirve si ni siquiera puede abrirlo? Si tan solo su padre le hubiera proporcionado la llave.
Padre -
package Dump;
public class Parent {
private String reallyHidden;
private String notReallyHidden;
public String getNotReallyHidden() {
return notReallyHidden;
}
public void setNotReallyHidden(String notReallyHidden) {
this.notReallyHidden = notReallyHidden;
}
}//Parent
Niño -
package Dump;
public class Child extends Parent {
private String childOnly;
public String getChildOnly() {
return childOnly;
}
public void setChildOnly(String childOnly) {
this.childOnly = childOnly;
}
public static void main(String [] args){
System.out.println("Testing...");
Child c1 = new Child();
c1.setChildOnly("childOnly");
c1.setNotReallyHidden("notReallyHidden");
//Attempting to access parent''s reallyHidden
c1.reallyHidden;//Does not even compile
}//main
}//Child
Depende de su definición de "heredar". ¿La subclase todavía tiene los campos en la memoria? Seguro. ¿Se puede acceder directamente a ellos? No. Es solo sutilezas de la definición; el punto es entender lo que realmente está sucediendo.
La mayor parte de la confusión en la pregunta / respuesta aquí envuelve la definición de herencia.
Obviamente, como @DigitalRoss explica que un OBJETO de una subclase debe contener los campos privados de su superclase. Como él dice, no tener acceso a un miembro privado no significa que no esté allí.
Sin embargo. Esto es diferente a la noción de herencia para una clase. Como es el caso en el mundo java, donde hay una cuestión de semántica, el árbitro es la Especificación del lenguaje Java (actualmente 3ª edición).
Como indica el JLS ( https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.2 ):
Los miembros de una clase que se declaran privados no son heredados por las subclases de esa clase. Solo los miembros de una clase que se declaran protegidos o públicos son heredados por subclases declaradas en un paquete que no sea aquel en el que se declara la clase.
Esto aborda la pregunta exacta planteada por el entrevistador: "las CLASES secundarias heredan campos privados". (énfasis agregado por mi)
La respuesta es No. No lo hacen. Los objetos de las subclases contienen campos privados de sus superclases. La subclase en sí no tiene NINGUNA NOCIÓN de campos privados de su superclase.
¿Es semántica de carácter pedante? Sí. ¿Es una pregunta de entrevista útil? Probablemente no. Pero el JLS establece la definición para el mundo Java, y lo hace (en este caso) de manera inequívoca.
EDITADO (eliminó una cita paralela de Bjarne Stroustrup que, debido a las diferencias entre java y c ++, probablemente solo se sume a la confusión. Dejaré que mi respuesta descanse en el JLS :)
Los miembros privados (estado y comportamiento) son heredados. Pueden (pueden) afectar el comportamiento y el tamaño del objeto que es instanciado por la clase. Sin mencionar que son muy visibles para las subclases a través de todos los mecanismos de ruptura de la encaptulación que están disponibles, o que pueden ser asumidos por sus implementadores.
Aunque la herencia tiene una definición de "facto", definitivamente no tiene ningún vínculo con los aspectos de "visibilidad", que se asumen con las respuestas "no".
Por lo tanto, no hay necesidad de ser diplomático. JLS está mal en este punto.
Cualquier suposición de que no son "heredados" es insegura y peligrosa.
Entonces, entre dos definiciones de hecho (parcialmente) en conflicto (que no repetiré), la única que debe seguirse es la que es más segura (o segura).
No. Los campos privados no se heredan ... y por eso se inventó Protected . Es por diseño. Supongo que esto justifica la existencia de modificador protegido.
Ahora llegando a los contextos. ¿Qué quiere decir con heredado, si está en el objeto creado a partir de una clase derivada? sí lo es.
Si quieres decir puede ser útil para la clase derivada. Bueno no.
Ahora, cuando llega a la programación funcional, el campo privado de la superclase no se hereda de manera significativa para la subclase . Para la subclase, un campo privado de súper clase es lo mismo que un campo privado de cualquier otra clase.
Funcionalmente, no se hereda. Pero idealmente , lo es.
OK, solo miré en el tutorial de Java que citan esto:
Miembros privados en una Superclase
Una subclase no hereda a los miembros privados de su clase padre. Sin embargo, si la superclase tiene métodos públicos o protegidos para acceder a sus campos privados, la subclase también puede utilizarlos.
Consulte: javadoc
Estoy de acuerdo, que el campo está ahí. Pero, la subclase no obtiene ningún privilegio en ese campo privado. Para una subclase, el campo privado es el mismo que cualquier campo privado de cualquier otra clase.
Creo que es puramente una cuestión de punto de vista. Puedes moldear el argumento a ambos lados. Es mejor justificar en ambos sentidos.
No. No lo heredan.
El hecho de que alguna otra clase pueda usarlo indirectamente no dice nada sobre la herencia, sino sobre la encapsulación.
Por ejemplo:
class Some {
private int count;
public void increment() {
count++;
}
public String toString() {
return Integer.toString( count );
}
}
class UseIt {
void useIt() {
Some s = new Some();
s.increment();
s.increment();
s.increment();
int v = Integer.parseInt( s.toString() );
// hey, can you say you inherit it?
}
}
También puede obtener el valor de count
dentro de UseIt
través de la reflexión. No significa, lo heredas.
ACTUALIZAR
Aunque el valor está ahí, no es heredado por la subclase.
Por ejemplo, una subclase definida como:
class SomeOther extends Some {
private int count = 1000;
@Override
public void increment() {
super.increment();
count *= 10000;
}
}
class UseIt {
public static void main( String ... args ) {
s = new SomeOther();
s.increment();
s.increment();
s.increment();
v = Integer.parseInt( s.toString() );
// what is the value of v?
}
}
Esta es exactamente la misma situación que el primer ejemplo. El count
atributos está oculto y la subclase no lo hereda en absoluto. Aún así, como señala DigitalRoss, el valor está ahí, pero no por medio de la herencia.
Ponlo de esta manera. Si tu padre es rico y te da una tarjeta de crédito, todavía puedes comprar algo con su dinero, pero eso no significa que hayas heredado todo ese dinero, ¿verdad?
Otra actualización
Sin embargo, es muy interesante saber por qué el atributo está ahí.
Francamente, no tengo el término exacto para describirlo, pero es la JVM y la forma en que funciona lo que carga también la definición principal "no heredada".
De hecho, podríamos cambiar el padre y la subclase seguirá funcionando.
//A.java
class A {
private int i;
public String toString() { return ""+ i; }
}
// B.java
class B extends A {}
// Main.java
class Main {
public static void main( String [] args ) {
System.out.println( new B().toString() );
}
}
// Compile all the files
javac A.java B.java Main.java
// Run Main
java Main
// Outout is 0 as expected as B is using the A ''toString'' definition
0
// Change A.java
class A {
public String toString() {
return "Nothing here";
}
}
// Recompile ONLY A.java
javac A.java
java Main
// B wasn''t modified and yet it shows a different behaviour, this is not due to
// inheritance but the way Java loads the class
Output: Nothing here
Supongo que el término exacto se puede encontrar aquí: La especificación de la máquina virtual JavaTM
Ok, este es un problema muy interesante que investigué mucho y llegué a la conclusión de que los miembros privados de una superclase están realmente disponibles (pero no son accesibles) en los objetos de la subclase. Para probar esto, aquí hay un código de ejemplo con una clase primaria y una clase secundaria y estoy escribiendo un objeto de clase secundaria en un archivo txt y leyendo un miembro privado llamado ''bhavesh'' en el archivo, por lo tanto, estoy demostrando que está disponible en el niño clase pero no accesible debido al modificador de acceso.
import java.io.Serializable;
public class ParentClass implements Serializable {
public ParentClass() {
}
public int a=32131,b,c;
private int bhavesh=5555,rr,weq,refw;
}
import java.io.*;
import java.io.Serializable;
public class ChildClass extends ParentClass{
public ChildClass() {
super();
}
public static void main(String[] args) {
ChildClass childObj = new ChildClass();
ObjectOutputStream oos;
try {
oos = new ObjectOutputStream(new FileOutputStream("C://MyData1.txt"));
oos.writeObject(childObj); //Writing child class object and not parent class object
System.out.println("Writing complete !");
} catch (IOException e) {
}
}
}
Abra MyData1.txt y busque el miembro privado llamado ''bhavesh''. Por favor díganme que piensan.
Parecería que una subclase hereda los campos privados en que estos mismos campos se utilizan en el funcionamiento interno de la subclase (hablando filosóficamente). Una subclase, en su constructor, llama al constructor de superclase. Los campos privados de superclase obviamente son heredados por la subclase que llama al constructor de superclase si el constructor de superclase ha inicializado estos campos en su constructor. Eso es solo un ejemplo. Pero, por supuesto, sin los métodos de acceso, la subclase no puede acceder a los campos privados de la superclase (es como no poder abrir el panel posterior de un iPhone para extraer la batería y reiniciar el teléfono ... pero la batería aún está allí).
Una de las muchas definiciones de herencia que he encontrado: "Herencia - una técnica de programación que permite a una clase derivada extender la funcionalidad de una clase base, heredando todo su ESTADO (el énfasis es mío) y su comportamiento".
Los campos privados, incluso si no son accesibles por la subclase, son el estado heredado de la superclase.
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. https://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6
Simplemente podemos afirmar que cuando una superclase se hereda, los miembros privados de la superclase realmente se convierten en miembros privados de la subclase y no pueden heredarse más o son inaccesibles para los objetos de la subclase.
Tendría que responder que los campos privados en Java son heredados. Permítame demostrar:
public class Foo {
private int x; // This is the private field.
public Foo() {
x = 0; // Sets int x to 0.
}
//The following methods are declared "final" so that they can''t be overridden.
public final void update() { x++; } // Increments x by 1.
public final int getX() { return x; } // Returns the x value.
}
public class Bar extends Foo {
public Bar() {
super(); // Because this extends a class with a constructor, it is required to run before anything else.
update(); //Runs the inherited update() method twice
update();
System.out.println(getX()); // Prints the inherited "x" int.
}
}
Si ejecuta en un programa Bar bar = new Bar();
, entonces siempre verá el número "2" en el cuadro de salida. Debido a que el entero "x" está encapsulado con los métodos update()
y getX()
, entonces se puede probar que el entero se hereda.
La confusión es que debido a que no se puede acceder directamente al entero "x", las personas argumentan que no se hereda. Sin embargo, todo lo no estático de una clase, ya sea campo o método, se hereda.
Una subclase no hereda a los miembros privados de su clase padre. Sin embargo, si la superclase tiene métodos públicos o protegidos para acceder a sus campos privados, la subclase también puede utilizarlos.
No , los campos privados no se heredan. La única razón es que la subclase no puede acceder a ellos directamente .