2010-10-20 5 views
4

Voici un extrait de mon codeAppel de la méthode parent à partir de la classe parente

package dictionary; 

import java.util.Iterator; 
import java.util.LinkedList; 
import java.util.regex.*; 

public class IntelliCwDB extends CwDB { 

    public IntelliCwDB(String filename) { 
     super(filename); 
    } 

    @Override 
    public void add(String word, String clue) { 
     System.out.println("inelli"); 
    } 
} 

Et CwDB ...

package dictionary; 

import java.util.LinkedList; 
import java.io.*; 
import java.util.Scanner; 

public class CwDB { 
    protected LinkedList<Entry> dict; 

    public CwDB(String filename) { 
     dict = new LinkedList<Entry>(); 
     createDB(filename); 
    } 

    public void add(String word, String clue) { 
     System.out.println("cwdb"); 
     dict.add(new Entry(word, clue)); 
    } 

    protected void createDB(String filename) { 
     try { 
      BufferedReader f = new BufferedReader(new FileReader(filename)); 
      while (f.ready()) { 
       this.add(f.readLine(), f.readLine()); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Dans la partie main() créer un nouvel objet IntelliCwDB, qui tire la exécution de createDB(). Le problème est que je veux CwDB.createDB() pour utiliser sa propre méthode CwDB.add(), pas celle de IntelliCwDB. Existe-t-il une autre solution intéressante que de créer CwDB séparément, puis de le passer dans le constructeur de IntelliCwDB juste pour réécrire la base de données dict LinkedList<Entry>?

Répondre

2

Vous pouvez le résoudre comme ceci:

  • Créer une version privée (ou définitive) du CwDB.add, permet de l'appeler privateAdd.

  • Laissez l'ancienne méthode add dans CwDB appeler cette méthode à la place.

  • Chaque fois que vous voulez être sûr que le CwDB -version de add est utilisé, vous appelez simplement privateAdd au lieu.

Exemple de code

public class CwDB { 

    // ... 

    public void add(String word, String clue) { 
     privateAdd(word, clue); 
    } 

    private void privateAdd(String word, String clue) { 
     System.out.println("cwdb"); 
     dict.add(new Entry(word, clue)); 
    } 

    protected void createDB(String filename) { 
     // ... 
      // "Calling parent method from within the parent class" :-) 
      this.privateAdd(f.readLine(), f.readLine()); 
     // ... 
    } 

    // ... 
} 

Comme @ Péter Török souligne à juste titre: Vous ne devriez jamais appeler une méthode virtuelle (directement ou indirectement) à partir d'un constructeur. La raison est simple: la sous-classe va exécuter le code avant que sa super classe (et elle-même) soit initialisée correctement. (Si oui ou non il applique dans cet exemple particulier va de soi cependant.)

+0

Java est ambigu dans ce cas, à cause de ce que je comprends, le passage de CwDB.add() à IntelliCwDB.add() dans CwDB constructeur est fait en silence (ou pour être précis - le commutateur qui n'a pas encore été effectué). Ne vaut-il pas mieux désactiver complètement ces opérations? Sont-ils réellement utiles dans la programmation normale? – krzemian

+0

Hmm .. Je ne suis pas sûr de ce que vous voulez dire. Le "switch" n'est jamais fait. Toutes les méthodes sont * toujours * virtuelles, depuis le début, même dans le constructeur. Qu'est-ce que vous suggérez de désactiver? Substitution de méthode? En C++, vous avez la possibilité de rendre une méthode non virtuelle (comme vous semblez vouloir dans ce scénario). Java a adopté une autre approche et a rendu toutes les méthodes virtuelles, sans avoir la possibilité de les désactiver. – aioobe

1

Je propose la méthode add-addInternal dans CwDB, et de faire une nouvelle add qui appelle addInternal. Ensuite, dans la méthode createDB, appelez addInternal pour obtenir la méthode correcte. Par exemple.

class CwDB { 
    .. 
    private void addInternal(String word, String clue) { 
    .. 
    } 

    public void add(String word, String clue) { 
    addInternal(word, clue); 
    } 

    public void createDB(String filename) { 
     .. 
     addInternal(w, c); 
     .. 
    } 
} 
+0

Vous devez mentionner qu'il doit rendre l'ajout interne privé pour s'assurer qu'il n'est pas écrasé. – aioobe

+0

C'est vrai, je l'ai fait dans le code d'exemple. – andrewmu

3

Vous avez vécu l'une des raisons pour lesquelles on ne doit pas appeler des méthodes virtuelles à partir d'un constructeur. Pour plus de détails à ce sujet, voir Effective Java 2nd Edition, article 17: Concevoir et documenter pour l'héritage ou bien l'interdire. La solution la plus simple à votre problème serait de diviser la méthode de la classe de base en une méthode non virtuelle (final et/ou private) et une autre, virtuelle, qui appelle la première dans l'implémentation de la classe de base.

@aioobe était plus rapide pour donner un exemple à ce :-)

+2

La plupart des belles questions abstraites sont sur qui est le plus rapide sur le tirage au sort :) – andrewmu

+0

"plus rapide sur le tirage au sort" ,, hahah – aioobe

Questions connexes