Я разрабатываю клиент-сервер в java, и я столкнулся с проблемой передачи пользовательской реализации Runnable в качестве аргумента от объекта другому. Проблема в том, что исполняемый код оценивается (не выполняется) при определении, но я хочу, чтобы он оценивался при вызове. Есть ли способ добиться такого поведения?
Вот код, затронутый этой проблемой:
- Пользовательская реализация Runnable
public abstract class ChallengeReportDelegation implements Runnable
{
private ChallengeReport fromChallengeReport = null;
private ChallengeReport toChallengeReport = null;
@Override
public abstract void run();
public ChallengeReport getFromChallengeReport()
{
return fromChallengeReport;
}
public ChallengeReport getToChallengeReport()
{
return toChallengeReport;
}
public void setFromChallengeReport(ChallengeReport fromChallengeReport)
{
this.fromChallengeReport = fromChallengeReport;
}
public void setToChallengeReport(ChallengeReport toChallengeReport)
{
this.toChallengeReport = toChallengeReport;
}
}
- Здесь, где Runnable передается в качестве аргумента:
// Record challenge
this.challengesManager.recordChallenge(whoSentRequest, whoConfirmedRequest,
new ChallengeReportDelegation()
{
@Override
public void run()
{
ChallengeReport fromReport = getFromChallengeReport();
ChallengeReport toReport = getToChallengeReport();
sendMessage(whoSentRequest, new Message(MessageType.CHALLENGE_REPORT, String.valueOf(fromReport.winStatus), String.valueOf(fromReport.challengeProgress), String.valueOf(fromReport.scoreGain)));
sendMessage(whoConfirmedRequest, new Message(MessageType.CHALLENGE_REPORT, String.valueOf(toReport.winStatus), String.valueOf(toReport.challengeProgress), String.valueOf(toReport.scoreGain)));
}
});
- Принимающий объект сохраняет экземпляр
ChallengeReportDelegation
как completionOperation
, подождите тайм-аут, затем выполните этот код.
private void complete()
{
stopTranslations();
int fromStatus;
int toStatus;
if (this.fromScore > this.toScore)
{
fromStatus = 1;
toStatus = -1;
}
else if (this.fromScore < this.toScore)
{
fromStatus = -1;
toStatus = 1;
}
else
{
fromStatus = 0;
toStatus = 0;
}
this.completionOperation.setFromChallengeReport(new ChallengeReport(this.from, fromStatus,this.fromTranslationsProgress, this.fromScore));
this.completionOperation.setToChallengeReport(new ChallengeReport(this.to, toStatus, this.toTranslationsProgress, this.toScore));
this.completionOperation.run();
}
Приведенный выше код вызывает NullPointerException
при выполнении последней части кода в методе run.
[EDIT]
Исключение NullPointerException
выбрасывается, поскольку оба getFromChallengeReport()
и getToChallengeReport()
(вторая часть кода) первоначально возвращает ноль (когда Runnable определен и передан в качестве аргумента), но они будут возвращать согласованные значения во время вызова run()
(третья часть кода)
[ РЕДАКТИРОВАТЬ2]
Я воспроизвел ситуацию в следующем простом коде:
public class TestEvaluation
{
public static void main(String[] args) throws InterruptedException
{
Middle middle = new Middle();
middle.register(new Task() {
@Override
public void run() {
System.out.println("a is: " + getA());
System.out.println("b is: " + getB());
}
});
Thread.sleep(2000);
}
abstract static class Task implements Runnable
{
private int a = 0;
private int b = 0;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
@Override
abstract public void run();
}
static class Middle
{
private ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor(1);
public void register(Task task)
{
Leaf leaf = new Leaf(new Task() {
@Override
public void run() {
System.out.println("Middle");
task.run();
}
});
pool.schedule(leaf, 1, TimeUnit.SECONDS);
}
}
static class Leaf implements Runnable
{
public Task task;
public Leaf(Task task)
{
this.task = task;
}
@Override
public void run()
{
task.setA(5);
task.setB(5);
System.out.println("Leaf");
task.run();
}
}
}
Поведение, которое я хочу достичь, это печать
Leaf
Middle
a is: 5
b is: 5
Но это то, что я получаю
Leaf
Middle
a is: 0
b is: 0