Pourquoi attribuons-nous une référence parent à l'objet enfant en Java?


Je pose une question assez simple, mais je suis un peu confus à ce sujet.

Supposons que j'ai une classe Parent:

public class Parent {

    int name;
}

Et avoir une autre classe Child.java:

public class Child extends Parent{

    int salary;
}

Et enfin mon Principal.classe java

public class Main {

    public static void main(String[] args)
    {
        Parent parent = new Child();
        parent.name= "abcd";
    }
}

Si je fais un objet enfant comme

Child child = new Child():

Alors child l'objet peut accéder aux deux variables name and salary.

Ma question est:

Parent parent = new Child();

Donne l'accès uniquement à la variable name de la classe parent. Alors quelle est l'utilisation exacte de cela ligne??

 Parent parent = new Child();

Et aussi quand il utilise le polymorphisme dynamique alors pourquoi la variable de la classe enfant n'est pas accessible après avoir fait cela

Parent parent = new Child();
Author: Roman C, 2012-08-28

8 answers

Tout d'abord, une clarification de la terminologie: nous attribuons un Child objet à une variable de type Parent. Parent est une référence à un objet qui se trouve être un sous-type de Parent, un Child.

, Il n'est utile que dans un exemple plus compliqué. Imaginez que vous ajoutiez getEmployeeDetails au parent de la classe:

public String getEmployeeDetails() {
    return "Name: " + name;
}

Nous pourrions remplacer cette méthode dans Child pour fournir plus de détails:

@Override
public String getEmployeeDetails() {
    return "Name: " + name + " Salary: " + salary;
}

Maintenant, vous pouvez écrire une ligne de code qui obtient tous les détails disponibles, que l'objet soit un Parent ou Child:

parent.getEmployeeDetails();

Le code suivant:

Parent parent = new Parent();
parent.name = 1;
Child child = new Child();
child.name = 2;
child.salary = 2000;
Parent[] employees = new Parent[] { parent, child };
for (Parent employee : employees) {
    employee.getEmployeeDetails();
}

Entraînera la sortie:

Name: 1
Name: 2 Salary: 2000

, Nous avons utilisé un Child comme Parent. Il avait un comportement spécialisé unique à la classe Child, mais lorsque nous avons appelé getEmployeeDetails(), nous pouvions ignorer la différence et nous concentrer sur la façon dont Parent et Child sont similaires. C'est ce qu'on appelle polymorphisme de sous-type.

Votre question mise à jour demande pourquoi Child.salaryn'est pas accessible lorsque l'objet Child est stocké dans une référence Parent. La réponse est l'intersection du " polymorphisme "et du"typage statique". Parce que Java est typé statiquement au moment de la compilation, vous obtenez certaines garanties du compilateur mais vous êtes obligé de suivre des règles en échange ou le code ne compilera pas. Ici, la garantie pertinente est que chaque instance d'un sous-type (par exemple Child) peut être utilisée comme instance de son supertype (par exemple Parent). Par exemple, vous avez la garantie que lorsque vous accédez à employee.getEmployeeDetails ou employee.name, la méthode ou le champ est défini sur tout objet non nul qui pourrait être affectée à une variable employee de type Parent. Pour faire cette garantie, le compilateur ne considère que ce type statique (essentiellement, le type de la référence de variable, Parent) lorsqu'il décide à quoi vous pouvez accéder. Vous ne pouvez donc pas accéder aux membres définis sur le type d'exécution de l'objet, Child.

Lorsque vous voulez vraiment utiliser un Child comme Parent ceci est un simple restriction à vivre avec et votre code sera utilisable pour Parent et l'ensemble de ses sous-types. Lorsque cela n'est pas acceptable, faites le type de la référence Child.

 36
Author: John Watts, 2017-10-26 15:36:55

Il vous permet d'accéder à toutes les sous-classes via une interface parent commune. Ceci est bénéfique pour l'exécution d'opérations communes disponibles sur toutes les sous-classes. Un meilleur exemple est nécessaire:

public class Shape
{
  private int x, y;
  public void draw();
}

public class Rectangle extends Shape
{ 
  public void draw();
  public void doRectangleAction();
}

Maintenant, si vous avez:

List<Shape> myShapes = new ArrayList<Shape>();

Vous pouvez référencer chaque élément de la liste comme une forme, vous n'avez pas à vous soucier s'il s'agit d'un Rectangle ou d'un autre type comme disons Cercle. Vous pouvez les traiter tous de la même manière; vous pouvez tous les dessiner. Vous ne pouvez pas appeler doRectangleAction parce que vous ne savez pas si la Forme est vraiment un rectangle.

Il s'agit d'un échange que vous faites entre le traitement des objets de manière générique et le traitement spécifique.

Vraiment, je pense que vous devez en savoir plus sur la POO. Un bon livre devrait aider: http://www.amazon.com/Design-Patterns-Explained-Perspective-Object-Oriented/dp/0201715945

 10
Author: anio, 2012-08-28 12:57:30

Si vous affectez type parent d'une sous-classe, cela signifie que vous acceptez d'utiliser les caractéristiques communes de la classe parent.

Il vous donne la liberté de faire abstraction de différentes implémentations de sous-classe. En conséquence, vous limite avec les fonctionnalités parentes.

Cependant, ce type d'affectation est appelé upcasting.

Parent parent = new Child();  

Le contraire est downcasting.

Child child = (Child)parent;

Donc, si vous créez une instance de Child et abattu à Parent, vous pouvez utiliser l'attribut type name. Si vous créez une instance de Parent, vous pouvez faire la même chose qu'avec le cas précédent mais vous ne pouvez pas utiliser salary car il n'y a pas un tel attribut dans le Parent. Revenez au cas précédent qui peut utiliser salary mais seulement si le downcasting à Child.

Il y a une explication plus détaillée

 6
Author: Roman C, 2012-08-28 18:30:53

Lorsque vous compilez votre programme, la variable de référence de la classe de base obtient de la mémoire et le compilateur vérifie toutes les méthodes de cette classe. Il vérifie donc toutes les méthodes de classe de base mais pas les méthodes de classe enfant. Maintenant, lors de l'exécution lorsque l'objet est créé, seules les méthodes vérifiées peuvent s'exécuter. Dans le cas où une méthode est remplacée dans la classe enfant, cette fonction s'exécute. Classe enfant les autres fonctions ne sont pas exécutées car le compilateur ne les a pas reconnues au moment de la compilation.

 5
Author: Akshat Chaturvedi, 2018-01-16 22:06:38

C'est simple.

Parent parent = new Child();

, Dans ce cas, le type de l'objet est Parent. Ant Parent n'a qu'une seule propriété. C'est name.

Child child = new Child();

Et dans ce cas, le type de l'objet est Child. Ant Child a deux propriétés. Ils sont name et salary.

Le fait est qu'il n'est pas nécessaire d'initialiser un champ non final immédiatement à la déclaration. Habituellement, cela se fait au moment de l'exécution car souvent vous ne pouvez pas savoir exactement de quelle implémentation exactement vous aurez besoin. Exemple imaginez que vous ayez une hiérarchie de classes avec class Transport en tête. Et de trois sous-classes: Car, Helicopter et Boat. Et il y a une autre classe Tour qui a le champ Transport. C'est-à-dire:

class Tour {
   Transport transport;
}  

Tant qu'un utilisateur n'a pas réservé de voyage et n'a pas choisi un type de transport particulier, vous ne pouvez pas initialiser ce champ. C'est le premier.

Deuxièmement, supposons que toutes ces classes doivent avoir une méthode go() mais avec une implémentation différente. Vous pouvez définir une implémentation de base en par défaut dans la superclasse Transport et propres implémentations uniques dans chaque sous-classe. Avec cette initialisation Transport tran; tran = new Car();, vous pouvez appeler la méthode tran.go() et obtenir le résultat sans vous soucier de l'implémentation spécifique. Il appellera une méthode surchargée à partir d'une sous-classe particulière.

De plus, vous pouvez utiliser une instance de sous-classe partout où une instance de superclasse est utilisée. Par exemple, vous voulez fournir la possibilité de louer votre transport. Si vous n'utilisez pas de polymorphisme, vous devez écrire beaucoup de méthodes pour chaque cas: rentCar(Car car), rentBoat(Boat boat) et ainsi de suite. Dans le même temps, le polymorphisme vous permet de créer une méthode universelle rent(Transport transport). Vous pouvez y passer l'objet de n'importe quelle sous-classe de Transport. De plus, si au fil du temps votre logique augmentera et que vous devrez créer une autre classe dans la hiérarchie? Lorsque vous utilisez le polymorphisme, vous n'avez rien à changer. Il suffit d'étendre la classe Transport et de passer votre nouvelle classe dans la méthode:

public class Airplane extends Transport {
    //implementation
}

Et rent(new Airplane()). Et new Airplane().go() dans le second cas.

 4
Author: kapand, 2012-08-28 17:21:03

Supposons que vous souhaitiez avoir un tableau d'instances de la classe Parent et un ensemble de classes enfants Child1, Child2, Child3 étendant Parent. Il y a des situations où vous n'êtes intéressé que par l'implémentation de la classe parent, qui est plus générale, et ne vous souciez pas de des choses plus spécifiques introduites par les classes enfants.

 1
Author: soliloquyy, 2012-08-28 12:57:41

Cette situation se produit lorsque vous avez plusieurs implémentations. Laissez-moi vous expliquer. Supposons que vous ayez plusieurs algorithmes de tri et que vous souhaitiez choisir au moment de l'exécution celui à implémenter, ou que vous souhaitiez donner à quelqu'un d'autre la possibilité d'ajouter son implémentation. Pour résoudre ce problème, vous créez généralement une classe abstraite (Parent) et avez une implémentation différente (Enfant). Si vous écrivez:

Child c = new Child();

Vous liez votre implémentation à la classe enfant et vous ne pouvez plus la changer. Sinon, si vous utilisez:

Parent p = new Child();

Tant que Child étend Parent, vous pouvez le changer à l'avenir sans modifier le code.

La même chose peut être faite en utilisant des interfaces: Parent n'est plus une classe mais une interface java.

En général, vous pouvez utiliser cette approche dans le modèle DAO où vous souhaitez avoir plusieurs implémentations dépendantes de la base de données. Vous pouvez jeter un oeil à FactoryPatter ou AbstractFactory Pattern. J'espère que cela peut vous aider.

 1
Author: FrancescoAzzola, 2012-08-28 12:57:44

Vous déclarez parent comme Parent, donc java ne fournira que les méthodes et les attributs de la classe Parent.

Child child = new Child();

Devrait fonctionner. Ou

Parent child = new Child();
((Child)child).salary = 1;
 -6
Author: Thargor, 2012-08-28 12:51:58