Java: конструктор копирования не работает как запланировано - PullRequest
0 голосов
/ 24 октября 2011

У меня есть небольшая проблема.Я делаю проверку конечных автоматов.При заданном входе и DFA он заканчивается в состоянии принятия.

Моя проблема заключается в создании нового DFA_State из чужой цели.

DFA_State state0, state1, curr_state, init_state, temp; //fine, I think
state0 = new DFA_State();
state1 = new DFA_State();
state0 = new DFA_State("State 0",true, state0, state1); //fine, I think
init_state = new DFA_State(state0);  //fine, I think

, но этот бит вызывает проблемы.

temp = new DFA_State(curr_state.nextState(arr1[i]));
*
*
curr_state = new DFA_State(temp);

Спасибо за любую помощь, Дейв

Редактировать: Боже, я был отсталым, когда я это сделал, AFAIK, я просто не думал прямо, добавил методы для установки значений вобъект DFA_State.

//in DFA_State class
public void set(DFA_State on_0, DFA_State on_1, Boolean is_accepting, String name){
    this.on_0 = on_0;
    this.on_1 = on_1;
    this.is_accepting = is_accepting;
    this.name = name;
}
//in main
DFA_State state0, state1, curr_state; 
state0 = new DFA_State();
state1 = new DFA_State();
state0.set(state0, state1, false, "State 0");
state1.set(state1, state0, true, "State 1");

curr_state = state0;//initial state
//iterate across string input changing curr_state depending on char c
curr_state = getNextState(c);
//at end
if(curr_state.isAccepting()) 
    System.out.println("Valid, " + curr_state.getName() + " is accepting);
else 
    System.out.println("Invalid, " + curr_state.getName() + " is not accepting);

Ответы [ 4 ]

0 голосов
/ 25 октября 2011

Хорошо, мы знаем, что это домашнее задание.Давайте сделаем это вместо того, чтобы сказать вам ответ, давайте попробуем проработать его самостоятельно.Если вы видите исключение NullPointerException (NPE).Возьмите вторую строку исключения:

java.lang.NullPointerException: null
   at com.blah.blah.SomeObject.someMethod(SomeArgumentType):1234 <<< here
   ....

Это 1234 - номер строки в файле, который содержит SomeObject.Если вы перейдете на этот номер строки, вы сможете точно определить, откуда генерируется NPE.Например, если строка 1234 была:

this.foo = bar.indexOf("caramel");

Вы можете легко определить, что было нулем.Понятия не имею?Ну, this никогда не может быть нулевым, поэтому this.foo не проблема.Если this может быть нулевым, вы не можете быть внутри этого метода, потому что this указывает на экземпляр, в котором вы находитесь в данный момент.Следовательно, единственным другим оператором, где переменная разыменовывается, является bar, поэтому bar должно быть нулевым.Давайте посмотрим на ваш код:

temp = new DFA_State(curr_state.nextState(arr1[i]));

Скажем, вы обнаружили, что строка выше вызывает исключение.Ну, может быть несколько вещей, которые могут быть нулевыми.curr_state может быть нулевым, или arr1 может быть нулевым, и в этом случае эта строка будет взорвана.Однако, если arr1 [i] равен null или curr_state.nextState () возвращает null, вы не увидите, что NPE указывает на эту строку, но будет выходить из конструктора, если кто-то попытается вызвать методы для этого параметра метода.

Надеемся, что это даст вам инструменты, необходимые для отслеживания проблем в вашем приложении, благодаря пониманию трассировки стека исключений.

0 голосов
/ 24 октября 2011

Представления DFA в памяти лучше, чем объектно-ориентированные.

Вы должны использовать простую таблицу поиска:

int[] table = new int[vocabularyCount][stateCount];

Каждое состояние и каждое слово получают число, начиная с 0Заполните таблицу переходами между состояниями или -1, если переходов нет.Теперь вам просто нужны методы перевода состояний и слов.

Вот общий алгоритм DFA:

public boolean checkSentence(String s, int[] finishes) {
    // fill table

    int state = 0; // assuming S0 is the start state
    for (int i = 0; i < s.length(); i++) {
        state = table[translate(s.charAt(i))][s];
    }

    for (int i = 0; i < finishes.length; i++) {
        if (finishes[i] == state) {
            return true;
        }
    }

    return false;
}
0 голосов
/ 24 октября 2011

Программа написана довольно плохо.Посмотрите на это в вашем FoundationsOfComputing.java:

    state0 = new DFA_State();
    state1 = new DFA_State();

    state0 = new DFA_State("State 0",true, state0, state1);

Вы по сути создали 3 экземпляра состояния - два экземпляра, которые не инициализированы (первые две строки в вашем коде) - все их переменные экземпляра равны нулю.

Затем вы создаете третий экземпляр, который указывает на первые два неинициализированных экземпляра, и присваиваете его переменной state0.Обратите внимание, что на данный момент изменяется только значение переменной, а не значения, которые вы передали в конструктор DFA-State !!!Итак, то, что у вас теперь есть в state0, это состояние, которое указывает на два неинициализированных состояния.

Теперь давайте посмотрим на код ниже в FoundationsOfComputing.java:

    while (i < arr1.length) {//loops through array
        System.out.println(i + ". scan shows " + arr1[i]);
        temp = new DFA_State(curr_state.nextState(arr1[i]));
        System.out.println("   "+curr_state.get_name()+ " moves onto " + temp.get_name());
        curr_state = new DFA_State(temp);
        i++;
    }

Я предполагаюэто вызывает NullPointerException - этот код переходит в состояние on_0 для state0 - это состояние, которое не было инициализировано (все его переменные экземпляра имеют значение null), поэтому на следующем этапе цикла, когда он вызывает curr_state.nextState (что угодно), он вернет ноль, и вы пытаетесь передать это конструктору копирования, что приведет к NPE.

0 голосов
/ 24 октября 2011

В первой строке вы объявляете переменные state0, state1, curr_state, init_state и temp как переменные типа DFA_State.Однако, это только объявляет их, они еще не инициализированы.Следующие несколько строк все в порядке.Вторая строка создает состояние без чего-либо в нем и присваивает его state0, как и третья строка для state1.Четвертая строка перезаписывает ваше предыдущее назначение state0 новым DFA_State, имеющим фактическое содержание.Пятая строка создает DFA_State в качестве копии state0 и присваивает ее init_state.

Предполагая, что между этой строкой и первой строкой вашего второго блока кода нет ничего, теперь вы получитепроблема.Вы присваиваете temp с новым DFA_State, который использует конструктор копирования с аргументом, основанным на curr_state.Но на тот момент эта переменная еще не была инициализирована.То, что это было объявлено, не означает, что оно каким-то образом уже структурировано в памяти.Когда вы вызываете nextState для него, просто нет переменной, чтобы разрешить это.Не ожидайте получить что-то вроде указателя, который в конечном итоге будет указывать на часть того, что вы вставили в curr_state.

Я просто догадываюсь, но из вашего стиля кода я бы сказал, что у вас естьфон в C или C ++.Посмотрите на различия между этими языками и Java.Если возможно, я бы также посоветовал вам сделать ваш класс DFA_State неизменным, поскольку это более надежно и позволит избежать ошибок.Это означает избавление от конструктора без аргументов.Вот его доработка (на самом деле не скомпилированная, может содержать ошибки):

package foundations.of.computing;

/**
 *
 * @author Kayotic
 */
class DFA_State {
    private final String state;
    private final DFA_State on_0;
    private final DFA_State on_1;
    private final boolean isAccepting;
    //private DFA_State dummy;

    public DFA_State(DFA_State arg) {
        //this(arg.is_accepting(), arg.on0(), arg.on1());
        state = arg.get_name();
        isAccepting = arg.is_accepting();
        on_0 = arg.on0();
        on_1 = arg.on1();
    }

    public DFA_State(String name, Boolean accepting, DFA_State on0, DFA_State on1) {
        state = name;
        isAccepting = accepting;
        on_0 = on0;
        on_1 = on1;
    }

    public String get_name(){
        return state;
    }


    public Boolean is_accepting() {
        return isAccepting;
    }

    public DFA_State on0() {
        return on_0;
    }

    public DFA_State on1() {
        return on_1;
    }

    public DFA_State nextState(char i) {
        if (i == '0') {
            return on0();
        } else if (i == '1') {
            return on1();
        } else {
            System.out.println("Error with input");
            return null;
        }
    }
}

Даже если вы не можете сделать переменные экземпляра окончательными, лучше по крайней мере сделать их закрытыми, так как у вас уже есть методыдля их получения.

...