web-dev-qa-db-fra.com

Les sous-classes héritent-elles de champs privés?

Ceci est une question d'entrevue.

Les sous-classes héritent-elles des champs privés?

J'ai répondu "Non", car nous ne pouvons pas y accéder à l'aide de la méthode "normale OOP". Mais l'intervieweur pense qu'ils sont hérités, car nous pouvons accéder à de tels champs indirectement ou en utilisant la réflexion et ils existent toujours dans l'objet.

Après mon retour, j'ai trouvé la citation suivante dans le javadoc :

Membres privés dans une superclasse

Une sous-classe n'hérite pas des membres privés de sa classe parente.

Connaissez-vous des arguments pour l'opinion de l'intervieweur?

227
Stan Kurilin

La plupart de la confusion dans la question/réponses ici entoure la définition de l'héritage.

Évidemment, comme l'explique @DigitalRoss, un OBJET d'une sous-classe doit contenir les champs privés de sa super-classe. Comme il le dit, ne pas avoir accès à un membre privé ne veut pas dire qu'il n'est pas là.

Pourtant. Ceci est différent de la notion d'héritage pour une classe. Comme dans le monde Java, où il est question de sémantique, l'arbitre est le spécification du langage Java (actuellement 3e édition).

Comme l'indique le JLS ( https://docs.Oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.2 ):

Les membres d'une classe déclarée privée ne sont pas hérités par les sous-classes de cette classe. Seuls les membres d'une classe déclarée protégée ou publique sont hérités par des sous-classes déclarées dans un package autre que celui dans lequel la classe est déclarée.

Cela répond à la question exacte posée par l'intervieweur: "les sous-classes ()) héritent-elles des champs privés". (italique ajouté par moi)

La réponse est non. Ils ne le font pas. Les OBJETS des sous-classes contiennent des champs privés de leurs super-classes. La sous-classe elle-même n'a AUCUN NOTION de champs privés de sa superclasse.

Est-ce une sémantique de nature pédante? Oui. Est-ce une question d'entrevue utile? Probablement pas. Mais le JLS établit la définition du monde Java et il le fait (dans ce cas) sans ambiguïté.

EDITED (suppression d'une citation parallèle de Bjarne Stroustrup qui, en raison des différences entre Java et c ++, ne fait qu'ajouter à la confusion. Je laisserai ma réponse reposer sur le JLS :)

224
robert_x44

Oui

Il est important de réaliser que même sisontdeux classes, il n'y a qu'un seul objet.

Donc, oui, bien sûr, il a hérité des champs privés. Ils sont vraisemblablement essentiels au bon fonctionnement des objets. Bien qu’un objet de la classe parente ne soit pas un objet de la classe dérivée, une instance de la classe dérivée est généralement une instance de la classe parente. Cela ne pourrait très bien être que sans tous les champs.

Non, vous ne pouvez pas y accéder directement. Oui, ils sont hérités. Ilsontêtre.

C'est une bonne question!


Mise à jour:

Euh, "non"

Eh bien, je suppose que nous avons tous appris quelque chose. Comme JLS est à l'origine du libellé exact "pas hérité", il est correct de répondre"no". Étant donné que la sous-classe ne peut pas accéder aux champs privés ni les modifier, alors, en d'autres termes, ils ne sont pas hérités. Mais il y a vraimentestjusteunobjet, c'est vraimentcontientles champs privés, donc si quelqu'un prend le JLS et le libellé du didacticiel dans le mauvais sens, il sera assez difficile de comprendre les objets OOP, Java et ce qui se passe réellement.

Mise à jour pour mettre à jour:

La controverse ici implique une ambiguïté fondamentale:de quoi parle-t-on exactement?Leobjet?Ou parlons-nous une certaine signification à propos dela classe elle-même?/ Une grande latitude est permise pour décrire la classe par opposition à l'objet. Ainsi, la sous-classe n'hérite pas des champs privés, mais d'un objet qui est une instance de la sous-classe certainement/contientles champs privés.

73
DigitalRoss

Non. Les champs privés ne sont pas hérités ... et c'est pourquoi Protégé a été inventé. C'est par conception. Je suppose que cela a justifié l’existence d’un modificateur protégé.


J'arrive maintenant aux contextes. Que voulez-vous dire par hérité - s’il existe dans l’objet créé à partir de la classe dérivée? Oui, ça l'est.

Si vous voulez dire peut-il être utile de classe dérivée. Et bien non.

Maintenant, quand vous arrivez à la programmation fonctionnelle , le champ privé de la super classe n’est pas hérité de manière significative pour la sous-classe . Pour la sous-classe, un champ privé de super classe est identique à un champ privé de toute autre classe.

Fonctionnellement, ce n'est pas hérité. Mais idéalement , c’est.


OK, je viens de regarder dans Java tutoriel ils citent ceci:

Membres privés dans une superclasse

Une sous-classe n'hérite pas des membres privés de sa classe parente. Toutefois, si la superclasse dispose de méthodes publiques ou protégées pour accéder à ses champs privés, celles-ci peuvent également être utilisées par la sous-classe.

se référer: http://download.Oracle.com/javase/tutorial/Java/IandI/subclasses.html

Je suis d'accord, que le champ est là. Cependant, la sous-classe ne reçoit aucun privilège sur ce champ privé. Pour une sous-classe, le champ privé est identique à tout champ privé de toute autre classe.

Je crois que c'est purement une question de point de vue. Vous pouvez modeler l’argument d’un côté ou de l’autre. Il vaut mieux justifier les deux sens.

18
Nishant

Cela dépend de votre définition de "hériter". La sous-classe a-t-elle toujours les champs en mémoire? Absolument. Peut-il y accéder directement? Non, ce ne sont que des subtilités de la définition; le but est de comprendre ce qui se passe réellement.

11
Mehrdad

Je vais démontrer le concept avec du code. Les sous-classes ACTUALLY héritent des variables privées de la super classe. Le seul problème est qu’ils ne sont pas accessibles aux objets enfants, à moins que vous ne fournissiez des getters et des setters publics pour les variables privées de la super-classe.

Considérons deux classes dans le package Dump. L'enfant étend le parent.

Si je me souviens bien, un objet enfant en mémoire est constitué de deux régions. L'un est la partie parent uniquement et l'autre est la partie enfant uniquement. Un enfant peut accéder à la section privée du code de son parent uniquement via une méthode publique dans le parent.

Pense-y de cette façon. Le père de Borat, Boltok, a un coffre-fort contenant 100 000 dollars. Il ne veut pas partager sa variable "privée" en toute sécurité. Il ne fournit donc pas de clé pour le coffre-fort. Borat hérite du coffre-fort. Mais à quoi sert-il s'il ne peut même pas l'ouvrir? Si seulement son père avait fourni la clé.

Parent -

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

Enfant -

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
Borat Sagdiyev

Non, ils n'en héritent pas.

Le fait qu'une autre classe puisse l'utiliser indirectement ne dit rien sur l'héritage, mais sur l'encapsulation.

Par exemple:

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?
     }
}

Vous pouvez également obtenir la valeur de count à l'intérieur de UseIt par réflexion. Cela ne signifie pas, vous en héritez.

UPDATE

Même si la valeur est là, elle n’est pas héritée par la sous-classe.

Par exemple, une sous-classe définie comme:

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?           
     }
}

C'est exactement la même situation que dans le premier exemple. L'attribut count est caché et n'est pas hérité par la sous-classe. Pourtant, comme le souligne DigitalRoss, la valeur est là, mais pas par le biais de l’héritage.

Mets le comme ça. Si votre père est riche et vous donne une carte de crédit, vous pouvez toujours acheter quelque chose avec son argent, mais cela ne signifie pas que vous avez hérité tout cet argent, n'est-ce pas?

Autre mise à jour

C'est très intéressant cependant, savoir pourquoi l'attribut est là.

Franchement, je n'ai pas le terme exact pour le décrire, mais c'est la JVM et son fonctionnement qui chargent également la définition du parent "non hérité".

Nous pourrions en fait changer le parent et la sous-classe fonctionnera toujours.

Par exemple :

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

Je suppose que le terme exact pourrait être trouvé ici: spécification de la machine virtuelle JavaTM

9
OscarRyz

Eh bien, ma réponse à la question de l'intervieweur est - Les membres privés ne sont pas hérités dans des sous-classes, mais ils ne sont accessibles aux objets de sous-classes ou de sous-classes que via des méthodes de lecture ou de définition publiques ou toute méthode appropriée de la classe d'origine. La pratique normale est de garder les membres privés et d'y accéder à l'aide de méthodes getter et setter publiques. Alors à quoi sert-il d’hériter des méthodes getter et setter lorsque le membre privé avec lequel elles traitent n’est pas disponible pour l’objet? Ici, "hérité" signifie simplement qu'il est disponible directement dans la sous-classe et qu'il peut être utilisé avec les méthodes nouvellement introduites dans la sous-classe.

Enregistrez le fichier ci-dessous sous le nom ParentClass.Java et essayez vous-même ->

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 nous essayons d'utiliser la variable privée x de ParentClass dans la méthode de SubClass, elle n'est directement accessible pour aucune modification (signifie non hérité). Mais x peut être modifié dans SubClass via la méthode setX () de la classe originale, comme dans la méthode setXofParent () OR peut être modifié à l'aide d'un objet ChildClass à l'aide de la méthode setX () ou de la méthode setXofParent () qui appelle finalement setX () Donc ici, setX () et getX () sont des sortes de portes pour le membre privé x d'une ParentClass.

Un autre exemple simple est Clock superclass. Heures et minutes en tant que membre privé et méthodes de lecture et définition appropriées en tant que public. Vient ensuite DigitalClock en tant que sous-classe de Clock. Ici, si l’objet de la DigitalClock ne contient pas d’heures et de minutes, les choses sont foutues.

6
dganesh2002

Ok, c’est un problème très intéressant sur lequel j’ai beaucoup cherché. Je suis parvenu à la conclusion que les membres privés d’une superclasse sont effectivement disponibles (mais non accessibles) dans les objets de la sous-classe. Pour le prouver, voici un exemple de code avec une classe parent et une classe enfant. J'écris un objet de classe enfant dans un fichier txt et lit un membre privé nommé 'bhavesh' dans le fichier, ce qui prouve qu'il est effectivement disponible dans l'enfant. classe mais non accessible en raison du modificateur d'accès.

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) {
    }


}
}

Ouvrez MyData1.txt et recherchez le membre privé nommé 'bhavesh'. S'il vous plaît laissez-moi savoir ce que vous en pensez.

4
Bhavesh Agarwal

Il semblerait qu'une sous-classe hérite des champs privés en ce sens que ces mêmes champs sont utilisés dans le fonctionnement interne de la sous-classe (philosophiquement parlant). Une sous-classe, dans son constructeur, appelle le constructeur de la super-classe. Les champs privés de la super-classe sont évidemment hérités par la sous-classe appelant le constructeur de la super-classe si le constructeur de la super-classe a initialisé ces champs dans son constructeur. C'est juste un exemple. Mais bien sûr, sans méthodes d’accessoires, la sous-classe ne peut pas accéder aux champs privés de la super-classe (c’est comme ne pas pouvoir ouvrir le panneau arrière d’un iPhone pour retirer la batterie et réinitialiser le téléphone ... mais la batterie est toujours là).

PS L'une des nombreuses définitions de l'héritage que j'ai rencontrées: "Héritage - une technique de programmation qui permet à une classe dérivée d'étendre les fonctionnalités d'une classe de base, en héritant de tout son état et de son comportement."

Les champs privés, même s'ils ne sont pas accessibles par la sous-classe, sont l'état hérité de la superclasse.

3
Flanker

Memory Layout in Java vis-a-vis inheritance

enter image description here

Les bits de remplissage/alignement et l'inclusion de la classe d'objet dans le VTABLE ne sont pas pris en compte. L'objet de la sous-classe a donc une place pour les membres privés de la classe Super. Cependant, il est impossible d'y accéder à partir des objets de la sous-classe ...

Non, les champs privés ne sont pas hérités. La seule raison est que la sous-classe ne peut pas y accéder directement.

1
joooohnli

Je devrais répondre que les champs privés dans Java sont hérités. Permettez-moi de démontrer:

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 vous exécutez un programme Bar bar = new Bar();, vous verrez toujours le nombre "2" dans la zone de sortie. Puisque l'entier "x" est encapsulé avec les méthodes update() et getX(), il peut être prouvé que l'entier est hérité.

La confusion est que parce que vous ne pouvez pas accéder directement au nombre entier "x", les gens prétendent qu'il n'est pas hérité. Cependant, chaque élément non statique d'une classe, qu'il s'agisse d'un champ ou d'une méthode, est hérité.

0
Lawful Lazy

Un membre de classe privé ou un constructeur n'est accessible que dans le corps de la classe de niveau supérieur ( §7.6 ) qui inclut la déclaration du membre ou du constructeur. Il n'est pas hérité par les sous-classes. https://docs.Oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6

0
mimibar

Je crois que la réponse dépend totalement de la question qui a été posée. Je veux dire, si la question est

Peut-on directement accéder au champ privé de la super-classe à partir de leur sous-classe?

Alors la réponse est Non , si nous passons par le détails du spécificateur d'accès , il est mentionné, les membres privés ne sont accessibles que dans le classe elle-même.

Mais, si la question est

Peut-on accéder au domaine privé de la super-classe à partir de leur sous-classe?

Ce qui signifie que peu importe ce que vous ferez pour accéder au membre privé. Dans ce cas, nous pouvons rendre la méthode publique dans la super-classe et vous pouvez accéder au membre privé. Donc, dans ce cas, vous créez une interface/un pont pour accéder au membre privé.

D'autres langages OOP comme C++ ont le concept friend function, grâce auquel nous pouvons accéder au membre privé de l'autre classe.

0
Ravi

Nous pouvons simplement dire que lorsqu'une superclasse est héritée, les membres privés de la superclasse deviennent en réalité des membres privés de la sous-classe et ne peuvent plus être hérités ou sont inaccessibles aux objets de la sous-classe.

0
Aamir wani