Reputation: 398
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
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
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
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