Доступ к переменным из внутреннего класса
У меня есть код, который определяет анонимный внутренний класс для обработчика обратного вызова. Этот обработчик должен назначить локальную переменную, см. Ниже. Мне нужно назначить 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());
}
}