在Java中,在匿名内部类中引用封闭类的非最终字段

3
在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。这是可行的,因为匿名类允许引用外部作用域中的final变量。
我不确定以下情况:
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指的是封闭类的非final字段。当Job运行时,我会看到问候语字段的值是在创建Job时还是在执行时?我想我知道答案,但我觉得这是一个有趣的问题,一开始让我和几个同事犹豫了几分钟。
3个回答

9

当匿名的Job执行时,您将看到greeting的值。

final修饰符仅适用于局部变量,而不适用于成员变量。


这就是我怀疑它是如何工作的。顺便说一句,我明确提到“非final”字段的唯一原因是,如果该字段是final,则行为是清晰的。 - Mike Daniels
是的。我们认为这是一个值得记录在SO上的好问题。Mike,你应该接受这个答案。 - Tim Bender

1

你正在通过(外部的)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();
    }
}

-1

final修饰符仅应用于局部变量,以为内部类的每个实例提供变量,因此我们使用: final String greeting;

当您仅需要一个变量实例(如常量或公共资源的情况)时,请使用: private String greeting;


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接