web-dev-qa-db-fra.com

Pourquoi attribue-t-on une référence parent à l'objet enfant en Java?

Je pose une question assez simple, mais je suis un peu confus à cet égard.

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 ma classe Main.Java

public class Main {

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

Si je crée un objet enfant comme

Child child = new Child():

Alors l'objet child peut accéder à la fois à name and salary variables.

Ma question est:

Parent parent = new Child();

donne uniquement l'accès à la variable name de la classe Parent. Alors, quelle est l'utilisation exacte de cette ligne?

 Parent parent = new Child();

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

Parent parent = new Child();
56
Narendra Pal

Premièrement, une clarification de la terminologie: nous assignons un objet Child à une variable de type Parent. Parent est une référence à un objet qui se trouve être un sous-type de Parent, un Child.

Ce n'est utile que dans un exemple plus compliqué. Imaginez que vous ajoutez getEmployeeDetails à la classe Parent:

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 récupère toutes les informations 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 un Parent. Il avait un comportement spécialisé propre à la classe Child, mais lorsque nous appelions getEmployeeDetails(), nous pouvions ignorer la différence et nous concentrer sur la façon dont Parent et Child étaient similaires. . Ceci s'appelle polymorphisme de sous-type .

Votre question mise à jour demande pourquoi Child.salary N'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 respecter les règles ou le code ne sera pas compilé. Ici, la garantie pertinente est que chaque instance d’un sous-type (par exemple, Child) peut être utilisé 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 NULL pouvant être affecté à une variable employee de type Parent. Pour garantir cette garantie, le compilateur considère uniquement ce type statique (en gros, le type de référence de la variable, Parent) lorsque vous décidez de ce que vous pouvez accéder. Par conséquent, vous ne pouvez accéder aux membres définis dans le type d'exécution de l'objet, Child.

Lorsque vous voulez vraiment utiliser un Child comme un Parent c'est une restriction facile à vivre et votre code sera utilisable pour Parent et tous ses sous-types. Lorsque cela n’est pas acceptable, indiquez le type de la référence Child.

39
John Watts

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 en tant que forme. Vous n'avez pas à vous inquiéter s'il s'agit d'un rectangle ou d'un autre type du type cercle. Vous pouvez les traiter tout de même; vous pouvez tous les dessiner. Vous ne pouvez pas appeler doRectangleAction car vous ne savez pas si la forme est vraiment un rectangle.

C'est un métier que vous faites entre traiter des objets de manière générique et traiter de manière spécifique.

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

10
anio

Si vous affectez un type parent à une sous-classe, cela signifie que vous acceptez d'utiliser les fonctionnalités communes de la classe parent.

Cela vous donne la liberté d'abstraire des implémentations de sous-classes différentes. En conséquence, vous limite avec les fonctionnalités parent.

Cependant, ce type d’affectation s’appelle upcasting.

Parent parent = new Child();  

Le contraire est décroissant.

Child child = (Child)parent;

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

Il y a plus d'explications détaillées

7
Roman C

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. Donc, il vérifie toutes les méthodes de classe de base mais pas les méthodes de classe enfant. Désormais, lors de la création de l'objet, seules les méthodes cochées peuvent être exécutées. Si une méthode est remplacée dans la classe enfant exécutée par la fonction. Les autres fonctions de la classe enfant ne sont pas exécutées car le compilateur ne les a pas reconnues au moment de la compilation.

5
Akshat Chaturvedi

C'est simple.

Parent parent = new Child();

Dans ce cas, le type de l'objet est Parent. Ant Parent n'a qu'une 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 immédiatement le champ non final lors de la déclaration. Généralement, cela est fait au moment de l’exécution car vous ne pouvez souvent pas savoir exactement de quelle implémentation vous avez exactement besoin. Par exemple, imaginons que vous ayez une hiérarchie de classe avec la classe Transport en tête. Et trois sous-classes: Car, Helicopter et Boat. Et il y a une autre classe Tour qui a le champ Transport. C'est:

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 d'abord.

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 par défaut dans la superclasse Transport et posséder des 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 un résultat sans vous soucier d'une 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 souhaitez offrir la possibilité de louer votre moyen de transport. Si vous n'utilisez pas le polymorphisme, vous devez écrire un grand nombre 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 passer l'objet de n'importe quelle sous-classe de Transport. En outre, si au fil du temps, votre logique augmente et vous devez 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 à la méthode suivante:

public class Airplane extends Transport {
    //implementation
}

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

5
kapand

Cette situation se produit lorsque vous avez plusieurs implémentations. Laissez-moi expliquer. Supposons que vous avez plusieurs algorithmes de tri et que vous voulez choisir au moment de l'exécution celui qui doit être implémenté, ou que vous voulez donner à quelqu'un d'autre la possibilité d'ajouter sa mise en œuvre. Pour résoudre ce problème, vous créez généralement une classe abstraite (Parent) et avez une implémentation différente (Child). Si vous écrivez:

Child c = new Child();

vous liez votre implémentation à la classe Child 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 Java Interface.

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

2
FrancescoAzzola

Supposons que vous souhaitiez disposer d'un tableau d'occurrences de la classe Parent et d'un ensemble de classes enfants Child1, Child2, Child3 qui étend Parent. Il existe des situations où vous ne vous intéressez qu'à l'implémentation de la classe parent, ce qui est plus général, et que vous ne vous souciez pas de des choses plus spécifiques introduite par les classes enfants.

1
soliloquyy