Вызов родительского метода из родительского класса - PullRequest
4 голосов
/ 20 октября 2010

Вот выдержка из моего кода

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?

Ответы [ 3 ]

3 голосов
/ 20 октября 2010

Вы столкнулись с одной из причин, по которой не следует вызывать виртуальные методы из конструктора .Подробнее об этом см. Effective Java 2nd Edition , Item 17: Разработка и документация для наследования, или же запретите его .

Самое простое решение вашей проблемыразделить метод базового класса на невиртуальный (final и / или private) и другой, виртуальный метод, который вызывает первый в реализации базового класса.

@ aioobe был быстреепривести пример этого: -)

2 голосов
/ 20 октября 2010

Вы можете решить это так:

  • Создать приватную (или окончательную) версию 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éter Török: вы никогда не должны вызывать виртуальный метод (прямо или косвенно) из конструктора. Причина проста: подкласс будет запускать код до того, как его суперкласс (и он сам) будет правильно инициализирован. (Независимо от того, применимо ли это в этом конкретном примере, это разумно.)

1 голос
/ 20 октября 2010

Я бы переместил метод add в addInternal в CwDB и сделал бы новый 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);
      ..
   }
}
...