以下是我的代码摘录
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");
}
}
和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();
}
}
}
在main()
部分,我创建了一个新的IntelliCwDB
对象,它会触发createDB()
的执行。
问题在于我希望CwDB.createDB()
使用它自己的CwDB.add()
方法,而不是IntelliCwDB
中的方法。除了单独创建CwDB
之外,还有其他任何简洁的解决方案,然后将其传递到IntelliCwDB
的构造函数中,只是为了重写LinkedList<Entry>
dict数据库吗?
答案 0 :(得分:3)
您遇到了不应该从构造函数中调用虚方法的原因之一。有关详细信息,请参阅Effective Java 2nd Edition,第17项:设计和文档以继承或禁止它。
解决问题的最简单方法是将基类方法拆分为非虚拟(final
和/或private
)方法,另一种方法是将虚拟方法调用基类实现。
@aioobe更快地为此提供了一个例子: - )
答案 1 :(得分:2)
你可以这样解决:
创建CwDB.add
的私有(或最终)版本,我们称之为privateAdd
。
让add
中的旧CwDB
方法改为调用此方法。
每当您想确保使用CwDB
版本的add
时,您只需拨打privateAdd
即可。
示例代码
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());
// ...
}
// ...
}
正如@PéterTörök正确指出的那样:你永远不应该在构造函数中直接或间接地调用虚方法。原因很简单:子类将在其超类(及其自身)正确初始化之前运行代码。 (不管它是否适用于这个特定的例子,都可以说明理由。)
答案 2 :(得分:1)
我会将add
方法移至CwDB中的addInternal
,然后创建一个调用add
的新addInternal
。然后在createDB
方法中,调用addInternal
以获取正确的方法。
例如
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);
..
}
}