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 } }); }
当前回答
匿名内部类中的方法可以在生成该类的线程终止后调用。在您的示例中,内部类将在事件分派线程上调用,而不是在创建它的线程中调用。因此,变量的作用域是不同的。所以为了保护这样的变量赋值范围问题,你必须声明它们为final。
其他回答
您可以创建一个类级别的变量来获取返回值。我的意思是
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中粗糙的、有限版本的闭包),变量也会保留它在创建实例时所持有的值。
因为局部内部类既不是类的成员也不是包的成员,所以没有使用访问级别声明它。(但是要清楚的是,它自己的成员像普通类一样具有访问级别。)
匿名内部类中的方法可以在生成该类的线程终止后调用。在您的示例中,内部类将在事件分派线程上调用,而不是在创建它的线程中调用。因此,变量的作用域是不同的。所以为了保护这样的变量赋值范围问题,你必须声明它们为final。
在Java中,变量不仅可以作为参数,还可以作为类级字段,例如
public class Test
{
public final int a = 3;
或者作为一个局部变量
public static void main(String[] args)
{
final int a = 3;
如果希望访问和修改匿名类中的变量,则可能希望将该变量设置为外围类中的类级变量。
public class Test
{
public int a;
public void doSomething()
{
Runnable runnable =
new Runnable()
{
public void run()
{
System.out.println(a);
a = a+1;
}
};
}
}
你不能把一个变量作为final,然后给它一个新值。Final的意思就是:值是不可改变的和Final的。
由于它是最终的,Java可以安全地将其复制到本地匿名类。你没有得到对int的引用(特别是因为你在Java中不能有对int这样的原语的引用,只能引用对象)。
它只是将a的值复制到一个隐式int,在匿名类中称为a。
private void f(Button b, final int a[]) {
b.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
a[0] = a[0] * 5;
}
});
}
有一个技巧允许匿名类在外部作用域中更新数据。
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]);
// ...
推荐文章
- 在流中使用Java 8 foreach循环移动到下一项
- 访问限制:'Application'类型不是API(必需库rt.jar的限制)
- 用Java计算两个日期之间的天数
- 如何配置slf4j-simple
- 在Jar文件中运行类
- 带参数的可运行?
- 我如何得到一个字符串的前n个字符而不检查大小或出界?
- 我可以在Java中设置enum起始值吗?
- Java中的回调函数
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 在Java中,流相对于循环的优势是什么?
- Jersey在未找到InjectionManagerFactory时停止工作
- 在Java流是peek真的只是调试?
- Recyclerview不调用onCreateViewHolder
- 将JSON字符串转换为HashMap