Доступ к переменным из внутреннего класса

У меня есть код, который определяет анонимный внутренний класс для обработчика обратного вызова. Этот обработчик должен назначить локальную переменную, см. Ниже. Мне нужно назначить resp в обратном вызове и обратиться к нему в конце функции. Я получаю эту ошибку в Eclipse:

Конечная локальная переменная resp не может быть назначена, поскольку она определена в закрывающемся типе

Как я могу это исправить?

DoorResult unlockDoor(final LockableDoor door) {
    final UnlockDoorResponse resp;
    final boolean sent = sendRequest(new UnlockDoorRequest(door), 
       new ResponseAction() {
        public void execute(Session session) 
               throws TimedOutException, RetryException, RecoverException {
            session.watch(UNLOCK_DOOR);
            resp = (UnlockDoorResponse)session.watch(UNLOCK_DOOR);
        }
    });
    DoorResult result;
    if (!sent) {
        return DoorResult.COMMS_ERROR;
    }
    else {
        return DoorResult.valueOf(resp.getResponseCode());
    }
}

Ответ 1

Вот хак, который будет работать в вашем случае:

DoorResult unlockDoor(final LockableDoor door) {
    final UnlockDoorResponse resp[] = { null };
    final boolean sent = sendRequest(new UnlockDoorRequest(door), new ResponseAction() {
        public void execute(Session session)  throws TimedOutException, RetryException, RecoverException {
            session.watch(UNLOCK_DOOR);
            resp[0] = (UnlockDoorResponse)session.watch(UNLOCK_DOOR);
        }
    });
    DoorResult result;
    if (!sent) {
        return DoorResult.COMMS_ERROR;
    }
    else {
        return null == resp[0] ? null : DoorResult.valueOf(resp[0].getResponseCode());
    }
}

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

С уважением, Стан.

Ответ 2

Вы можете обойти это, создав класс-оболочку для ответа.

class ResponseWrapper {
    UnlockDoorResponse resp;
    void setResponse(UnlockDoorResponse resp) {
        this.resp = resp;
    }
    UnlockDoorResponse getResponse() {
        return resp;
    }
}

Затем ваш код будет выглядеть так:

final ResponseWrapper respWrap = new ResponseWrapper();
final boolean sent = sendRequest(new UnlockDoorRequest(door), new ResponseAction() {
    public void execute(Session session)  throws TimedOutException, RetryException, RecoverException {
        session.watch(UNLOCK_DOOR);
        respWrap.setResponse((UnlockDoorResponse)session.watch(UNLOCK_DOOR));
    }
 });
DoorResult result;
if (!sent) {
    return DoorResult.COMMS_ERROR;
}
else {
    return DoorResult.valueOf(respWrap.getResponse().getResponseCode());
}

Ответ 3

Предполагая, что это ваш код для изменения, как насчет изменения sendRequest и ResponseAction.execute, чтобы вернуть экземпляр UnlockDoorResponse

DoorResult unlockDoor(final LockableDoor door) {
    final UnlockDoorResponse resp = sendRequest(new UnlockDoorRequest(door), new ResponseAction() {
        public UnlockDoorResponse execute(Session session)  throws TimedOutException, RetryException, RecoverException {
            session.watch(UNLOCK_DOOR);
            return (UnlockDoorResponse)session.watch(UNLOCK_DOOR);
        }
    });
    if (resp == null) {
        return DoorResult.COMMS_ERROR;
    }
    else {
        return DoorResult.valueOf(resp.getResponseCode());
    }
}

Ответ 4

Если вы собираетесь возвращать результаты, используйте вместо имени анонимный внутренний класс. Все остальные варианты представлены IMHO уродливыми хаками (один сам признал; -)

(ОК, @Joel не предполагает, но вы можете изменить интерфейс, который вы реализуете)

Просто создайте экземпляр класса с getter для результата, он чист и требует только одного класса.

    class MyReponseAction implements ResponseAction {
        private UnlockDoorResponse response; 

        public void execute(Session session)  throws TimedOutException, RetryException, RecoverException {
           session.watch(UNLOCK_DOOR);
           response = (UnlockDoorResponse)session.watch(UNLOCK_DOOR);
        }

        UnlockDoorResponse getResponse() {
            return response;
        }
    }

   DoorResult unlockDoor(final LockableDoor door) {
        ResponseAction action = new MyResponseAction();
        final boolean sent = sendRequest(new UnlockDoorRequest(door), action);

        DoorResult result;
        if (!sent) {
            return DoorResult.COMMS_ERROR;
        }
        else {
            return DoorResult.valueOf(action.getResponse().getResponseCode());
        }
    }