Обращение к неконечным полям окружающего класса внутри анонимного внутреннего класса в Java

В Java я знаю, что можно сделать что-то вроде этого:

public class Greeter {
    public void greetEventually() {
        final String greeting = "Hello!";
        Job j = new Job() {
            public void run() {
                System.out.println(greeting);
            }
        };
        j.schedule();
    }
}

Это приведет к выполнению анонимного Job в какой-то момент в будущем. Это работает, потому что анонимным классам разрешено ссылаться на конечные переменные во внешней области видимости.

В чем я не уверен, так это в следующем случае:

public class Greeter {
    private String greeting;

    // ... Other methods that might mutate greeting ...

    public void greetEventually() {
        Job j = new Job() {
            public void run() {
                System.out.println(greeting);
            }
        };
        j.schedule();
    }
}

В этом случае мой анонимный Job относится к неконечному полю окружающего класса. Когда задание запустится, увижу ли я значение поля greeting таким, каким оно было при создании задания или во время его выполнения? Я думаю, что знаю ответ, но я подумал, что это интересный вопрос, и поначалу он заставил меня и пару коллег задуматься на несколько минут.


person Mike Daniels    schedule 12.02.2010    source источник


Ответы (3)


Вы увидите значение greeting таким, какое оно есть при выполнении анонимного Job.

Модификатор final требуется только для локальных переменных, а не для переменных-членов.

person erickson    schedule 12.02.2010
comment
Вот как я подозревал, что это работает. Кстати, единственная причина, по которой я прямо упомянул неконечные поля, заключается в том, что если поле является окончательным, поведение понятно. - person Mike Daniels; 12.02.2010
comment
Ага. Мы подумали, что было бы неплохо записать этот вопрос в SO. Майк, ты должен принять это. - person Tim Bender; 12.02.2010

Вы обращаетесь к полю через (внешний) this). Вы можете думать о this как о локальной переменной final. Только локальный final, объект, на который указывает, не является (обязательно) постоянным. Представьте себе локальную переменную с тем же значением, что и this, и она должна быть понятна.

public class Greeter {
    private String greeting;

    // ... Other methods that might mutate greeting ...

    public void greetEventually() {

        private final Greeter greeter = this; // <---

        Job j = new Job() {
            public void run() {
                System.out.println(   greeter.greeting   ); // <---
            }
        };
        j.schedule();
    }
}
person Tom Hawtin - tackline    schedule 12.02.2010

Модификатор final применяется к локальным переменным только для предоставления переменных для каждого экземпляра внутреннего класса, поэтому мы используем: final Приветствие строки;

Когда вам нужен только один экземпляр переменной (например, в случае констант или общих ресурсов), используйте: private String Greeting;

person MostafaEweda    schedule 12.02.2010