krzemian
krzemian

Reputation: 398

Calling parent method from within the parent class

Here's an excerpt from my code

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");
    }
}

And 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();
        }
    }
}

In the main() part I create a new IntelliCwDB object, which fires the execution of createDB().

The problem is that I want CwDB.createDB() to use it's own CwDB.add() method, not the one from IntelliCwDB. Is there any other neat solution than creating CwDB separately, then passing it into the constructor of IntelliCwDB just to rewrite the LinkedList<Entry> dict database?

Upvotes: 4

Views: 362

Answers (3)

aioobe
aioobe

Reputation: 421290

You could solve it like this:

  • Create a private (or final) version of the CwDB.add, lets call it privateAdd.

  • Let the old add method in CwDB call this method instead.

  • Whenever you want to be sure that the CwDB-version of add is used, you simply call privateAdd instead.

Sample 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());
        // ...
    }

    // ...
}

As @Péter Török correctly points out: You should never call a virtual method (directly or indirectly) from within a constructor. The reason is simple: The sub-class will get to run code before its super class (and itself) is initialized properly. (Whether or not it applies in this particular example stands to reason though.)

Upvotes: 2

P&#233;ter T&#246;r&#246;k
P&#233;ter T&#246;r&#246;k

Reputation: 116306

You experienced one of the reasons why one should not call virtual methods from a constructor. For more details on this, see Effective Java 2nd Edition, Item 17: Design and document for inheritance or else prohibit it.

The simplest solution to your problem would be to split the base class method into a nonvirtual (final and/or private) one, and another, virtual, method, which calls the former in the base class implementation.

@aioobe was faster to provide an example to this :-)

Upvotes: 3

andrewmu
andrewmu

Reputation: 14544

I would move the add method to addInternal in CwDB, and make a new add which calls addInternal. Then in the createDB method, call addInternal to get the correct method. Eg.

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);
      ..
   }
}

Upvotes: 1

Related Questions