7
votes

Java: possible d'avoir des références de classe finale mutuelles?

Disons que j'ai deux classes, nommées A et B, qui sont associées à chacune de telle sorte qu'il est plus pratique si l'objet de chaque classe contient une référence à l'autre. En d'autres termes, la classe A a une variable "B" de la classe B. La classe B a une variable "A" de classe A. De cette façon, le code de chaque classe a un accès facile à l'autre classe.

Y a-t-il un moyen de mettre en place cette association pour être "finale"? I.e. La variable B en classe A est la finale et la variable A dans la classe B est définitive? Il semble que la mise en place de ces références dans un constructeur (comme le serait requise par le mot-clé final) nécessite une sorte de référence circulaire illogique.

Ceci est plus d'une question conceptuelle qu'à une pratique pratique. Merci!


0 commentaires

3 Réponses :


6
votes

Comme une autre affiche indiquait que est est possible de le faire en faisant l'une des classes responsables de la construction de l'autre et de se passer dans le constructeur pour l'autre objet.

Cependant, cela se prête à des problèmes potentiels si vous souhaitez qu'une seule instance de la première classe correspond à une instance de la deuxième classe (laquelle il vous semble que vous le faites). Un autre objet pourrait potentiellement passer une référence existante à la première classe dans le constructeur pour la deuxième classe, permettant ainsi une situation invalide (la deuxième classe a maintenant une référence à une instance de la première classe qui fait référence à un différent instance de la deuxième classe).

Plus de problèmes potentiels surviennent lorsque vous estimez que le constructeur de la deuxième classe ne peut pas faire référence aux membres non initialisés de la première classe.

Ma suggestion est que si les deux classes sont si interdépendantes que vous voulez qu'ils ont chacun des références finales à l'autre, en font simplement la même classe . Ensuite, vous avez toujours reçu une dernière référence à l'autre objet: ceci .


1 commentaires

Combiner les deux classes n'aident pas. Les références circulaires peuvent et souvent se produisent avec des objets de la même classe. Considérez des nœuds dans un arbre où chaque nœud a une référence finale à ses parents et à ses enfants, ou de tenter de créer une liste immuable doublement liée avec des références finales aux nœuds suivants et précédents.



6
votes

Oui, c'est possible, si l'une des catégories est responsable de la création de l'instance de l'autre classe. Le premier constructeur peut transmettre une instance d'elle-même comme paramètre pour la deuxième classe.

public class A {
    final B b;
    public A() {
        b = new B(this);
    }
    public B getB() {
        return b;
    }
}
public class B {
    final A a;
    public B(A a) {
        this.a = a;
    }
}


3 commentaires

Bien que cette approche puisse fonctionner, il est probablement dangereux que le constructeur B reçoit une référence à un élément non encore entièrement construit. Supposons, par exemple, que A a eu un autre domaine initialisé après 'B', et que le constructeur B tente d'y accéder. Il obtiendra un objet non initialisé. Il en va de même pour appeler des méthodes d'un constructeur de B, ou si A est prolongé ultérieurement ... peut-être une refonte serait une meilleure option.


Un peu plus concis est d'avoir une classe une classe intérieure de l'autre. (Remarque: comme vous avez créé le B Constructor public, une autre classe d'un autre package pourrait construire un autre B pour toute instance de A (ou null !).)


Peut-être que le meilleur moyen serait de rendre la péril de l'emballage constructeurs et de fournir une sorte de méthode d'usine pour fournir A. de cette façon que personne ne peut abuser accidentellement les classes.



1
votes

Si vous utilisez un conteneur di, tel que GUICICE, vous pouvez l'occorer sans référence évidente passant à l'intérieur du constructeur - qui peut être sujette d'erreur comme indiqué avant.

Déclarez la dépendance A-B et B-A et injecter un d'entre eux dans une autre classe. Guice fera une certaine magie pour permettre aux deux champs d'être définitifs. Fondamentalement, cela injectera d'abord un proxy et fixera sa délégatrice plus tard.

Avez-vous besoin d'un échantillon de code pour cela?


0 commentaires