a can only be final here. Why? How can I reassign a in onClick() method without keeping it as private member? private void f(Button b, final int a){ b.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { int b = a*5; } }); } How can I return the 5 * a when it clicked? I mean, private void f(Button b, final int a){ b.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { int b = a*5; return b; // but return type is void } }); }


当前回答

有一个技巧允许匿名类在外部作用域中更新数据。

private void f(Button b, final int a) {
    final int[] res = new int[1];
    b.addClickHandler(new ClickHandler() {
        @Override
        public void onClick(ClickEvent event) {
            res[0] = a * 5;
        }
    });

    // But at this point handler is most likely not executed yet!
    // How should we now res[0] is ready?
}

然而,由于同步问题,这个技巧不是很好。如果处理程序稍后被调用,你需要1)同步访问res,如果处理程序从不同的线程调用2)需要有某种标志或指示res被更新

但是,如果匿名类在同一个线程中立即被调用,这个技巧就可以工作。如:

// ...

final int[] res = new int[1];
Runnable r = new Runnable() { public void run() { res[0] = 123; } };
r.run();
System.out.println(res[0]);

// ...

其他回答

When an anonymous inner class is defined within the body of a method, all variables declared final in the scope of that method are accessible from within the inner class. For scalar values, once it has been assigned, the value of the final variable cannot change. For object values, the reference cannot change. This allows the Java compiler to "capture" the value of the variable at run-time and store a copy as a field in the inner class. Once the outer method has terminated and its stack frame has been removed, the original variable is gone but the inner class's private copy persists in the class's own memory.

(http://en.wikipedia.org/wiki/Final_%28Java%29)

Java内部类中的final变量[关于]

内部类只能使用

外部类引用 final局部变量来自范围外的引用类型(例如Object…) 值(原语)(例如int…)类型可以由最终引用类型包装。IntelliJ IDEA可以帮助您将其转换为一个元素数组

当编译器生成一个非静态嵌套(内部类)时-一个新类- <OuterClass>$<InnerClass>.class创建并将有界参数传递给构造函数[堆栈上的局部变量],它类似于闭包[Swift about]

Final变量是不能重新赋值的变量。最终引用变量仍然可以通过修改状态来更改

如果这是可能的,那就奇怪了,因为作为一个程序员,你可以做出这样的东西

//Not possible 
private void foo() {

    MyClass myClass = new MyClass(); //Case 1: myClass address is 1
    int a = 5;                       //Case 2: a = 5

    //just as an example
    new Button().addClickHandler(new ClickHandler() {
        
        @Override
        public void onClick(ClickEvent event) {

            /*
            myClass.something(); //<- what is the address - 1 or 2?
            int b = a; //<- what is the value - 5 or 10 ?

            //illusion that next changes are visible for Outer class
            myClass = new MyClass();
            a = 15;
            */
        }
    });

    myClass = new MyClass(); //Case 1: myClass address is 2
    int a = 10; //Case 2: a = 10
}

有一个技巧允许匿名类在外部作用域中更新数据。

private void f(Button b, final int a) {
    final int[] res = new int[1];
    b.addClickHandler(new ClickHandler() {
        @Override
        public void onClick(ClickEvent event) {
            res[0] = a * 5;
        }
    });

    // But at this point handler is most likely not executed yet!
    // How should we now res[0] is ready?
}

然而,由于同步问题,这个技巧不是很好。如果处理程序稍后被调用,你需要1)同步访问res,如果处理程序从不同的线程调用2)需要有某种标志或指示res被更新

但是,如果匿名类在同一个线程中立即被调用,这个技巧就可以工作。如:

// ...

final int[] res = new int[1];
Runnable r = new Runnable() { public void run() { res[0] = 123; } };
r.run();
System.out.println(res[0]);

// ...

由于Jon有实现细节的答案,另一个可能的答案是JVM不想处理已经结束他的激活的写入记录。

考虑这样一个用例,在这个用例中,你的lambdas不是被应用的,而是被存储在某个地方并稍后运行。

我记得在Smalltalk中,当你做这样的修改时,你会得到一个非法的商店。

您可以创建一个类级别的变量来获取返回值。我的意思是

class A {
    int k = 0;
    private void f(Button b, int a){
        b.addClickHandler(new ClickHandler() {
        @Override
        public void onClick(ClickEvent event) {
            k = a * 5;
        }
    });
}

现在你可以得到K的值,并在你想要的地方使用它。

你的答案是:

局部内部类实例绑定到Main类,可以访问其包含方法的最终局部变量。当实例使用其包含方法的final局部时,即使变量超出了作用域(这实际上是Java中粗糙的、有限版本的闭包),变量也会保留它在创建实例时所持有的值。

因为局部内部类既不是类的成员也不是包的成员,所以没有使用访问级别声明它。(但是要清楚的是,它自己的成员像普通类一样具有访问级别。)