¿Las subclases heredan campos privados?


245

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 son heredados, porque podemos acceder a dichos campos indirectamente o usando la reflexión y todavía existen en el objeto.

Cuando regresé, encontré la siguiente cita en el javadoc :

Miembros privados en una superclase

Una subclase no hereda los miembros privados de su clase principal.

¿Conoces algún argumento para la opinión del entrevistador?


33
Una vez estuve en una situación similar y me di cuenta de que ni siquiera quería trabajar para una compañía donde el entrevistador sabe menos sobre Java que yo. :)
biziclop

48
Un entrevistador a veces no estará de acuerdo con usted, incluso cuando sabe que tiene razón. Un buen entrevistador intentará aprender más sobre usted que sus conocimientos técnicos.
Andy Thomas

44
@DigitalRoss ¿La especificación del lenguaje Java también está mal escrita? Ver respuesta RD01: stackoverflow.com/questions/4716040/…
OscarRyz

99
@Andy Thomas-Cramer Tampoco me gustaría trabajar con personas que mienten deliberadamente para probar mi reacción.
biziclop

44
Bueno, creo que primero debemos descubrir el significado de "herencia" en Java. La subclase no tiene el campo privado y la subclase tiene el campo privado pero no puede acceder a él. ¿Cuál es el significado exacto de la herencia en Java?
MengT

Respuestas:


238

La mayor parte de la confusión en las preguntas / respuestas aquí rodea 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 de Java, donde hay una cuestión de semántica, el árbitro es la Especificación del lenguaje Java (actualmente 3ª edición).

Como dice 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 las 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 sub CLASAS heredan campos privados". (énfasis agregado por mí)

La respuesta es No. No lo hacen. Los OBJETOS de las subclases contienen campos privados de sus superclases. La subclase en sí NO tiene NOCIÓN de campos privados de su superclase.

¿Es la semántica de naturaleza pedante? Si. ¿Es una pregunta útil para la entrevista? Probablemente no. Pero el JLS establece la definición para el mundo Java, y lo hace (en este caso) sin ambigüedades.

EDITADO (eliminó una cita paralela de Bjarne Stroustrup que, debido a las diferencias entre java y c ++, probablemente solo aumente la confusión. Dejaré que mi respuesta descanse en el JLS :)


3
@digital por qué el suspiro. Entiendo que crees que tienes razón. No estoy en desacuerdo con usted en que la herencia de objetos es lo que a la mayoría de los programadores se les enseña / piensa. Pero la definición de JLS se aplica directamente a la pregunta original. Es la semántica sí, pero el JLS determina la definición, no tú o yo
Robert_x44

44
Una forma de conciliar todo esto es simplemente reconocer que la palabra "heredar" se usa de dos maneras muy diferentes para describir la relación de las clases derivadas y primarias, al menos en el mundo de Java. Sí, el JSL es autoritario. Sí, significa que puede usar "heredar" de esa manera desafortunada. Pero todavía es manifiestamente cierto que las subclases intercambian (porque ahora no tenemos una palabra) los campos privados de su clase principal.
DigitalRoss

1
@digital Están en el objeto de la clase. No la clase en sí. Simula los llamó objetos concatenados. Cuando se creó un objeto de una subclase, estaba formado por 'objetos prefijos' concatenados. El objeto de superclase era un objeto de prefijo que podía contener otros objetos de prefijo. Creo que es arrogancia decir que el JLS tiene "una redacción claramente mala". En cuanto a qué palabra usamos, herencia, por supuesto. No hay nada de malo en usar terminología ligeramente ambigua. Pasa todo el tiempo. Pero eso no significa que no haya una definición precisa.
robert_x44

1
@digital Ciertamente podemos estar de acuerdo en que la palabra se usa de diferentes maneras. :) También podemos estar de acuerdo en que una pregunta de entrevista que depende de un término ambiguo probablemente no sea buena.
robert_x44

2
¿Alguien tiene una referencia de Java / Oracle para "Los objetos de la subclase contienen los campos privados de sus superclases"? Estoy de acuerdo con esto, pero no puedo encontrar ningún documento oficial que lo diga.
MengT

78

si

Es importante darse cuenta de que si bien no son dos clases, sólo hay un objeto.

Entonces, sí, por supuesto, heredó los campos privados. Son, presumiblemente, esenciales para la funcionalidad adecuada del objeto, y aunque un objeto de la clase padre no es un objeto de la clase derivada, una instancia de la clase derivada es definitivamente una instancia de la clase padre. No podría ser eso sin todos los campos.

No, no puedes acceder directamente a ellos. Sí, son heredados. Ellos tienen que ser.

Es una buena pregunta!


Actualizar:

Err, "No"

Bueno, supongo que todos aprendimos algo. Dado que el JLS originó la redacción exacta "no heredada", es correcto responder "no" . Dado que la subclase no puede acceder o modificar los campos privados, en otras palabras, no se heredan. Pero en realidad es simplemente un objeto, lo que realmente contiene los campos privados, y por lo que si alguien toma las JLS y redacción tutorial de la manera incorrecta, será bastante difícil de entender programación orientada a objetos, objetos Java, y lo que está sucediendo realmente.

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 misma? Se permite mucha latitud cuando se describe la clase en lugar del objeto. Por lo tanto, la subclase no hereda los campos privados, pero un objeto que es una instancia de la subclase ciertamente contiene los campos privados.


2
@ Ma99uS. Por supuesto que se reutilizan. Ese es todo el punto de la herencia. Sin ellos, el tipo derivado no sería ni podría ser una instancia del tipo primario. OOP no tendría sentido. Los tipos polimórficos dejarían de funcionar . Comprender que solo hay un objeto y que ERES una instancia del tipo padre es crucial para comprender la POO. Debe superar este problema para comprenderlo en absoluto.
DigitalRoss

2
No estoy seguro de que el ejemplo del padre sea muy bueno porque un campo se puede heredar mientras la clase padre aún vive y también tiene ese campo. Si la herencia funcionara así, podría heredar el dinero de mi padre mientras él esté vivo y él podría quedarse con el mismo dinero también. Mis hijos tendrían cada uno su dinero y mi dinero.
Peter Lawrey

2
@ Peter Lawrey sin discutir ni nada, pero esto es lo que pienso. El padre tenía un car, lo mantuvo en un privatecasillero del cual el niño no tiene la llave. De hecho, heredas el carpero es inútil para ti. Entonces, prácticamente, no te estás beneficiando con la herencia.
Nishant

1
@DigitalRoss. Entiendo tu punto. Mhh, podríamos decir que el valor está ahí porque la definición principal no heredada también se carga. :) Creo que la especificación JVM tendría la respuesta correcta para esta "SIN PALABRA" que estamos buscando. java.sun.com/docs/books/jvms
OscarRyz

55
-1, la especificación del lenguaje Java explica claramente que no se heredan. Sin peros, sin peros. Simplemente no lo son. Cualquier otra definición de herencia es incorrecta en el contexto de Java.
biziclop

21

No. Los campos privados no se heredan ... y por eso se inventó Protected . Es por diseño. Supongo que esto justificó la existencia de un modificador protegido.


Ahora llegando a los contextos. ¿Qué quiere decir con heredado, si está allí en el objeto creado a partir de la clase derivada? sí lo es.

Si quiere decir, ¿puede ser útil para la clase derivada? Bueno no.

Ahora, cuando se trata de 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 superclase es igual a un campo privado de cualquier otra clase.

Funcionalmente, no se hereda. Pero idealmente , lo es.


OK, acabo de ver el tutorial de Java que citan esto:

Miembros privados en una superclase

Una subclase no hereda los miembros privados de su clase principal. Sin embargo, si la superclase tiene métodos públicos o protegidos para acceder a sus campos privados, estos también pueden ser utilizados por la subclase.

consulte: http://download.oracle.com/javase/tutorial/java/IandI/subclasses.html

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. Puede moldear el argumento a ambos lados. Es mejor justificar en ambos sentidos.

 


2
Esto no es correcto. No puedes acceder a ellos, eso es correcto. Pero tienen que ser heredados como he explicado.
DigitalRoss

1
excelente respuesta !!! +1 para I believe it's purely matter of point-of-view.yjustified the existence of protected modifier.
Ravi

14

Depende de su definición de "heredar". ¿La subclase todavía tiene los campos en la memoria? Seguro. ¿Puede acceder a ellos directamente? No. Son solo sutilezas de la definición; El punto es entender lo que realmente está sucediendo.


Correcto. Pero creo que en esa pregunta básica debería haber respuestas comunes)
Stan Kurilin

Creo que es la definición de herencia de Java.
OscarRyz

O bien, depende de su definición de "campo". Para definir un campo entero "foo" es alquilar un casillero de almacenamiento de tamaño entero y poner un signo "foo" en él. Si el campo se declara privado, la clase derivada hereda un casillero de almacenamiento de tamaño entero sin etiqueta. Si la clase derivada hereda o no el "campo" depende de si uno llama a ese casillero de almacenamiento sin etiqueta un "campo".
supercat

10

Demostraré el concepto con código. Las subclases REALMENTE heredan las variables privadas de la superclase. El único problema es que no son accesibles para los objetos secundarios a menos que proporcione captadores y establecedores públicos para las variables privadas en la superclase.

Considere dos clases en el paquete Dump. El niño extiende a los padres.

Si no recuerdo mal, un objeto hijo en la memoria consta de dos regiones. Uno es solo la parte principal y el otro 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. No quiere compartir su caja fuerte variable "privada". 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 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

10

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 del countinterior a UseIttravés de la reflexión. No significa, lo heredas.

ACTUALIZAR

Aunque el valor está ahí, la subclase no lo hereda.

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 atributo countestá oculto y la subclase no lo hereda en absoluto. Aún así, como señala DigitalRoss, el valor está ahí, pero no por herencia.

Ponlo de esta manera. Si tu padre es rico y te da una tarjeta de crédito, aún puedes comprar algo con su dinero, pero eso no significa que has 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 que también carga la definición principal "no heredada".

Realmente podríamos cambiar el padre y la subclase seguirá funcionando.

Por ejemplo :

//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

Creo que el término exacto se puede encontrar aquí: la especificación de máquina virtual JavaTM


:) La próxima vez que usted podría tener la oportunidad de explicar su entrevistador es donde él / ella incorrecto, y esto puede darle puntos extra;) Es evidente que debe hacer esto de una manera correcta diplomático.
OscarRyz

1
Ellos tienen que ser heredada de tipos polimórficos que tienen algún significado. Mira mi explicación. Es cierto que no puedes jugar con ellos, pero están ahí. Ellos tienen que ser.
DigitalRoss

No hay palabras clave de herencia (extiende / implementa) en su código, por lo que no es un ejemplo de herencia.
fmucar

1
Uhh, si están allí, ¿cómo llegaron allí? ¿Porque la subclase los definió? No. ¿Porque fueron, uhh, hmm, err, heredados ?
DigitalRoss

1
Gran punto sobre encapsulationvs inherit, supongo que esta respuesta merece más votos.
Eric Wang

6

Bueno, mi respuesta a la pregunta del entrevistador es: los miembros privados no se heredan en las subclases, pero son accesibles para la subclase o el objeto de la subclase solo a través de métodos públicos de captación o establecimiento o cualquier método apropiado de la clase original. La práctica normal es mantener la privacidad de los miembros y acceder a ellos utilizando métodos getter y setter que son públicos. Entonces, ¿cuál es el punto de heredar solo 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 métodos recién introducidos en la subclase.

Guarde el archivo a continuación 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, entonces no se puede acceder directamente a ninguna modificación (significa no heredado). Pero x se puede modificar en SubClass a través del 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 a 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 Clock tiene horas y minutos como miembros privados y los métodos getter y setter apropiados como públicos. Luego viene DigitalClock como una subclase de Clock. Aquí, si el objeto de DigitalClock no contiene horas y minutos miembros, entonces las cosas están jodidas.


2
Según el documento de Oracle: una subclase no hereda los miembros privados de su clase principal. Sin embargo, si la superclase tiene métodos públicos o protegidos para acceder a sus campos privados, estos también pueden ser utilizados por la subclase.
dganesh2002

4

Ok, este es un problema muy interesante. Investigué mucho y llegué a la conclusión de que los miembros privados de una superclase están realmente disponibles (pero no accesibles) en los objetos de la subclase. Para probar esto, aquí hay un código de muestra con una clase principal 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, demostrando que de hecho está disponible en el elemento secundario 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.


3

Parecería que una subclase hereda los campos privados en el sentido de que estos mismos campos se utilizan en el funcionamiento interno de la subclase (filosóficamente hablando). Una subclase, en su constructor, llama al constructor de la superclase. Los campos privados de la superclase obviamente son heredados por la subclase que llama al constructor de la superclase si el constructor de la superclase ha inicializado estos campos en su constructor. Eso es solo un ejemplo. Pero, por supuesto, sin 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 sacar la batería y reiniciar el teléfono ... pero la batería sigue ahí).

PD Una de las muchas definiciones de herencia que he encontrado: "Herencia: una técnica de programación que permite que una clase derivada extienda 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.


1

Tendría que responder que los campos privados en Java son heredados. Permítame demostrarle:

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 un programa Bar bar = new Bar();, siempre verá el número "2" en el cuadro de salida. Debido a que el entero "x" se encapsula con los métodos update()y getX(), entonces se puede demostrar que el entero se hereda.

La confusión es que debido a que no se puede acceder directamente al número entero "x", la gente argumenta que no se hereda. Sin embargo, cada cosa no estática en una clase, ya sea campo o método, se hereda.


3
"Contiene" no significa "hereda";)
Stan Kurilin

1

Diseño de memoria en Java frente a herencia

ingrese la descripción de la imagen aquí

Los bits de relleno / alineación y la inclusión de la clase de objeto en el VTABLE no se considera. Entonces, el objeto de la subclase tiene un lugar para los miembros privados de la Superclase. Sin embargo, no se puede acceder desde los objetos de la subclase ...


1

No , los campos privados no se heredan. La única razón es que la subclase no puede acceder a ellos directamente .


0

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 pasamos por los detalles del especificador de acceso , se menciona, los miembros privados solo son accesibles dentro de la clase misma.

Pero si la pregunta es

¿Podemos acceder al campo privado de la superclase desde su subclase?

Lo que significa que no importa lo que hagas para acceder al miembro privado. En ese caso, podemos hacer un método público en la superclase y 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 friend functionconcepto, por el cual podemos acceder al miembro privado de otra clase.


0

Simplemente podemos afirmar que cuando se hereda una superclase, los miembros privados de la superclase se convierten en miembros privados de la subclase y no pueden heredarse más o son inaccesibles para los objetos de la subclase.



-1

Una subclase no hereda los miembros privados de su clase principal. Sin embargo, si la superclase tiene métodos públicos o protegidos para acceder a sus campos privados, estos también pueden ser utilizados por la subclase.


-2

Los miembros privados (estado y comportamiento) se heredan. Pueden (pueden) afectar el comportamiento y el tamaño del objeto que la clase crea. Sin mencionar que son muy visibles para las subclases a través de todos los mecanismos de ruptura de encapsulación que están disponibles o 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".

Entonces, 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 conflictivas de facto (parcialmente) (que no repetiré), la única que debe seguirse es la más segura (o segura).


1
-1. El JLS define el lenguaje, es imposible que el JLS esté "equivocado". Además, si hay mecanismos que rompen la encapsulación, eso no significa que el campo se herede; simplemente que hay mecanismos que subvierten la encapsulación.
SL Barth - Restablece a Monica el

Una definición puede ser errónea en sí misma de varias maneras. Discutir más sobre esto no es mi intención. El argumento aquí no se trata de los mecanismos que rompen la encapsulación (por muy buenos o malos que sean) sino por el hecho de que el campo / método está allí, lo que afecta el comportamiento y el estado de su subclase. Entonces es "heredado". Se podría usar una matriz de bytes privada de 100 kb en una clase y simplemente asumir que sus descendientes (jumbo) no la heredan. No se pierda el punto y juzgue esto como una buena o mala práctica (la exageración ayuda a hacer un punto): es una acción legítima prevista. Los miembros privados SON "heredados".
gkakas
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.