2017-08-04 2 views
-1

D'abord, du contexte. Je reviens juste à Java après une pause de 2 ans que j'ai passé presque exclusivement à écrire des scripts en Python au travail. Malheureusement, je suis beaucoup plus rustre que ce à quoi je m'attendais. Comme une sorte de mise à jour, j'ai travaillé sur la construction d'une interface graphique pour un programme simple que j'ai écrit il y a quelque temps que j'utilise quotidiennement au travail. J'ai utilisé beaucoup de tutoriels et d'exemples de code sur le site Web d'Oracle pour aider à combler les lacunes dans ma mémoire de Java. En ce moment, je travaille sur la création d'une classe de dialogue personnalisée qui peut accepter, valider et renvoyer l'entrée de l'utilisateur. J'ai utilisé l'exemple de code this sur le site Oracle comme point de départ. La plupart du code a été très utile, mais je n'ai pu m'empêcher de remarquer une fuite de this dans le constructeur de la classe, ce qui semble étrange pour l'exemple de code fourni par Oracle. (Code ci-dessous)Fuite 'this' dans le constructeur de Java Tutorials Exemple de code pour CustomDialog.java

/** Creates the reusable dialog. */ 
public CustomDialog(Frame aFrame, String aWord, DialogDemo parent) { 
    super(aFrame, true); 
    dd = parent; 

    magicWord = aWord.toUpperCase(); 
    setTitle("Quiz"); 

    textField = new JTextField(10); 

    //Create an array of the text and components to be displayed. 
    String msgString1 = "What was Dr. SEUSS's real last name?"; 
    String msgString2 = "(The answer is \"" + magicWord 
          + "\".)"; 
    Object[] array = {msgString1, msgString2, textField}; 

    //Create an array specifying the number of dialog buttons 
    //and their text. 
    Object[] options = {btnString1, btnString2}; 

    //Create the JOptionPane. 
    optionPane = new JOptionPane(array, 
           JOptionPane.QUESTION_MESSAGE, 
           JOptionPane.YES_NO_OPTION, 
           null, 
           options, 
           options[0]); 

    //Make this dialog display it. 
    setContentPane(optionPane); 

    //Handle window closing correctly. 
    setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); 
    addWindowListener(new WindowAdapter() { 
      public void windowClosing(WindowEvent we) { 
      /* 
      * Instead of directly closing the window, 
      * we're going to change the JOptionPane's 
      * value property. 
      */ 
       optionPane.setValue(new Integer(
            JOptionPane.CLOSED_OPTION)); 
     } 
    }); 

    //Ensure the text field always gets the first focus. 
    addComponentListener(new ComponentAdapter() { 
     public void componentShown(ComponentEvent ce) { 
      textField.requestFocusInWindow(); 
     } 
    }); 

    **//Register an event handler that puts the text into the option pane. 
    textField.addActionListener(this); 

    //Register an event handler that reacts to option pane state changes. 
    optionPane.addPropertyChangeListener(this);** 
} 

Je dois admettre que je ne savais pas d'abord ce que la « fuite ce dans le constructeur » avertissement NetBeans voulait dire, mais je lu depuis this question, ce qui était utile; Cependant, je ne suis toujours pas sûr de la façon dont je pourrais procéder à l'enregistrement de ces gestionnaires d'événements d'une autre manière. Je ne m'inquiète pas vraiment des conséquences réelles que la fuite pourrait causer dans mon programme, mais j'aimerais savoir s'il y a une autre façon d'y parvenir. Considérant que cela a été fait de cette façon dans l'exemple de code d'un tutoriel Oracle Java, cela me porte à croire qu'il n'y a pas d'autre moyen évident de s'y prendre.

Note: ma question est pas « pourquoi fuit this dans le constructeur mauvaise pratique » ni « quelles sont les conséquences des fuites this dans le constructeur. » Je ne demande pas non plus pourquoi mon IDE (NetBeans) me donne cet avertissement. Ma question est plus préoccupé avec quelle autre façon d'enregistrer les gestionnaires d'événements dans la classe elle-même serait sans fuite this.

Répondre

2

Comme suggéré dans votre message mentionné ci-dessus, vous pouvez introduire une méthode de création statique, rendre le constructeur privé et déplacer les appels addXxxListener() à la méthode statique. Mais je laisserais le code tel qu'il est, peut-être avec une annotation @SuppressWarnings et un avertissement que les appels addXxxListener() devraient rester à la fin du constructeur. Après tout, c'est un avertissement sur un problème potentiel où le compilateur n'a pas l'intelligence de voir que l'instance est complètement terminée à ce point (au moins, dans un sens monothread - la sécurité multi-thread est une préoccupation différente) et toutes les autres classes qui verront l'objet prématurément verront effectivement une version terminée.

+0

Une méthode de création statique est logique. Merci pour le conseil. – wjjd225

+0

Je suis un peu confus à propos de ce qui se passe dans les coulisses tant que ces appels addXxxListener() vont quand ils sont dans le constructeur. Comment est-ce que la méthode addXxxListener() n'est pas exécutée jusqu'à ce que le constructeur soit fini? – wjjd225

+1

Il est exécuté avant la fin du constructeur - il est appelé depuis l'intérieur du constructeur. Mais cela ne fait pas de mal car la référence est déjà valide et ne changera plus. Le problème potentiel est que les champs de l'instance (et autre statut) ne sont pas encore complètement remplis jusqu'à l'état fini. Les appels addXxxListener() stockent simplement la référence quelque part pour une utilisation ultérieure, à appeler lorsque l'événement se produit. –