48 votes

Permettant cette référence à l'évasion

Je serais heureux d'aider dans la compréhension de la suite de "Java de la Simultanéité dans la Pratique":

L'appel d'une remplacable méthode d'instance(qui n'est ni privé, ni définitive) à partir du constructeur peut également permettre à l' cette référence à l'évasion.

  1. Ne "s'échapper" ici signifie simplement que l'on pourrait appeler une méthode d'instance,avant que l'instance est entièrement construit?
    Je ne vois pas " il " s'échapper de la portée de l'instance de toute autre manière.
  2. Comment 'final' empêcher que cela se produise?Est-il un aspect de la "finale" dans la création de l'instance que je suis absent?

27voto

SLaks Points 391154
  1. Cela signifie que le code appelant, en dehors de la classe, et en passant this.
    Ce code suppose que la classe est complètement initialisé, et peut se briser si elle ne l'est pas.
    De même, votre classe peut supposer que certaines méthodes ne sera appelée après la classe est complètement initialisé, mais le code externe est susceptible de briser ces hypothèses.

  2. final méthodes ne peuvent pas être remplacés, de sorte que vous pouvez leur faire confiance pour ne pas passer this autour de.
    Si vous appelez les non-final méthode dans le constructeur pour un non-final classe, une classe dérivée peut remplacer cette méthode et passer this n'importe où.
     
    Même lorsque vous appelez final méthodes, vous avez encore besoin pour s'assurer qu'ils sont en sécurité à l'écrit qu'ils ne passent pas this n'importe où, et qu'eux-mêmes ne pas appeler n'importe quel non-final méthodes.

22voto

chrylis Points 22655

"Escape" signifie qu'une référence à l'partiellement construits this objet peut être transmis à un autre objet dans le système. Considérez le scénario suivant:

public Foo {
    public Foo() {
        setup();
    }

    protected void setup() {
       // do stuff
    }
}

public Bar extends Foo implements SomeListener {
    @Override protected void setup() {
        otherObject.addListener(this);
    }
}

Le problème est que le nouveau Bar objet est enregistré avec otherObject avant que sa construction ne soit terminée. Maintenant, si otherObject commence à appeler des méthodes sur barObject, les champs n'aurait pas été initialisé, ou barObject , autrement, pourraient être dans un état incohérent. Une référence à l' barObject (this à lui-même) a "échappé" dans le reste du système avant qu'il soit prêt.

Au lieu de cela, si l' setup() méthode final sur Foo, l' Bar classe ne peut pas mettre de code dans là que va faire l'objet visible avant de l' Foo constructeur de finitions.

12voto

Sotirios Delimanolis Points 77933

Je crois que l'exemple est quelque chose comme

public class Foo {
    public Foo() {
        doSomething();
    }

    public void doSomething() {
        System.out.println("do something acceptable");
    }
}

public class Bar extends Foo {
    public void doSomething() {
        System.out.println("yolo");
        Zoom zoom = new Zoom(this); // at this point 'this' might not be fully initialized
    }
}

Parce que le super constructeur est toujours appelé en premier (implicitement ou explicitement), l' doSomething obtiendrez toujours appelé pour un enfant de la classe. Parce que la méthode ci-dessus n'est ni final ni private, vous pouvez le remplacer chez un enfant de la classe et de faire ce que vous voulez, ce qui peut entrer en conflit avec ce qu' Foo#doSomething() était censé faire.

5voto

Woot4Moo Points 14245

Par codage sécurisé

Exemple de MAUVAIS code:

final class Publisher {
  public static volatile Publisher published;
  int num;

  Publisher(int number) {
    published = this;
    // Initialization
    this.num = number;
    // ...
  }
}   

Si un objet d'initialisation (et, par conséquent, sa construction) dépend d'un contrôle de sécurité dans le constructeur, la vérification de la sécurité peut être contourné quand un non approuvés appelant obtient partiellement initialisé instance. Voir la règle OBJ11-J. Méfiez-vous de laisser les constructeurs de lancer des exceptions pour plus d'informations.

final class Publisher {
  public static Publisher published;
  int num;

  Publisher(int number) {
    // Initialization
    this.num = number;
    // ...
    published = this;
  }
}

Parce que le champ est non volatile et nonfinal, les instructions de le constructeur peut être réorganisées par le compilateur de telle manière que cette référence est publié avant l'initialisation déclarations avoir exécuté.

Bon code:

final class Publisher {
  static volatile Publisher published;
  int num;

  Publisher(int number) {
    // Initialization
    this.num = number;
    // ...
    published = this;
  }
}

Cette référence est dit avoir échappé lorsqu'il est mis à la disposition au-delà de son périmètre actuel. Suivants sont des moyens communs par lesquels le ce de référence peut échapper:

Returning this from a non-private, overridable method that is invoked from the constructor of a class whose object is being

construite. (Pour plus d'informations, voir la règle MET05-J. de s'Assurer que les constructeurs ne pas appeler les méthodes substituables.) Retourner ce à partir d'une méthode non privées d'une mutable classe, ce qui permet à l'appelant de manipuler l'état de l'objet indirect. Cette se produit généralement dans la méthode du chaînage des implémentations; voir la règle VNA04-J. S'assurer que les appels à enchaînés méthodes sont atomiques pour plus d'informations. En la passant comme argument pour un étranger de la méthode invoquée à partir du constructeur d'une classe dont l'objet est en cours de construction. En utilisant les classes internes. Un intérieur de classe implicitement contient une référence à l'instance de l'extérieur de la classe, sauf l'intérieur de la classe est déclarée statique. La publication par l'attribution de ce à un public statique de la variable dans le constructeur d'une classe dont l'objet est en cours de construction. Lancer une exception à partir d'un constructeur. Vous risqueriez de provoquer un code pour être vulnérable à un finaliseur attaque; voir la règle OBJ11-J. méfiez-vous de laisser les constructeurs de lancer des exceptions pour plus d'informations. Passage interne de l'état de l'objet à un étranger méthode. Cela permet à la méthode de récupérer la référence de l'intérieur de l'objet membre.

Cette règle décrit les conséquences potentielles de permettre à la ce référence à l'évasion durant de construction de l'objet, y compris la race les conditions et la mauvaise initialisation. Par exemple, la déclaration d'un champ final ordinairement assure que tous les threads, voir entièrement initialisé à l'état; toutefois, en permettant la cette référence à l'évasion pendant la construction de l'objet peut exposer le champ à d'autres threads dans un non initialisée ou partiellement initialisé à l'état. La règle TSM03-J. Ne pas publier partiellement les objets initialisés, qui décrit les garanties fournies par les différents mécanismes de sécurité de la publication, s'appuie sur la conformité à cette règle. Par conséquent, les programmes ne doivent pas permettre le cette référence à l'évasion durant de construction de l'objet.

En général, il est important de détecter les cas dans lesquels le ce de référence peut s'échapper au-delà de la portée du contexte actuel. Dans particulier, les variables et les méthodes doivent être soigneusement un examen minutieux.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X