gpt4 book ai didi

java - 事件调度线程的“局部变量需要声明为final”

转载 作者:行者123 更新时间:2023-12-01 06:56:56 26 4
gpt4 key购买 nike

我正在使用事件调度线程更新各种 swing 组件。但是,当我执行类似以下操作时,我收到错误 -

public Foo(User user) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
getNameTextField.setText(user.getName());
}
});
}

错误是 - “从内部类内部访问局部变量 user;需要声明为 Final”

这个问题的标准解决方案是什么......只是在每个函数参数之前加上final?

现在显然我不想将我的实际用户对象声明为最终的,因为我将来可能需要修改它。但是只在函数参数中的用户对象上设置final就可以了吗?

但是,当我将其设置为 Final 时,我实际上在做什么,因为它是对程序中“主”用户对象的引用。因此,同一个对象在一个地方被声明为最终对象,但在另一个地方则不是最终对象。声明它是最终的是否仅仅意味着对它的引用是最终的,但是用户对象本身可以自由修改?

最佳答案

解决方案是按照您的建议将函数参数设为最终值。

final 修饰符意味着在第一次赋值后不能重新分配引用。它不对所引用的对象提供任何保证。

顺便说一句,这是匿名内部类“嵌入”该语言的方式的产物。编译器为每个参数创建隐藏字段,如果您反编译上面的代码,您可以看到发生了什么......

在下面的反编译中,您会看到创建了一个新类 Foo$1 (foo 方法 #0),并且在第 #6 行,它在其构造函数中传递了 User arg。您会在 Foo$1.class 的反编译中看到类似的恶作剧叹息

由“Foo.java”编译

public class Foo extends java.lang.Object{

protected javax.swing.JTextField nameTextField;

public Foo();
Code:
0: aload_0
1: invokespecial #10; //Method java/lang/Object."<init>":()V
4: return

public void foo(User);
Code:
0: new #18; //class Foo$1
3: dup
4: aload_0
5: aload_1
6: invokespecial #20; //Method Foo$1."<init>":(LFoo;LUser;)V
9: invokestatic #23; //Method java/awt/EventQueue.invokeLater: (Ljava/lang/Runnable;)V
12: return

}

由“Foo.java”编译

class Foo$1 extends java.lang.Object implements java.lang.Runnable{
final Foo this$0;

private final User val$user;

Foo$1(Foo, User);
Code:
0: aload_0
1: aload_1
2: putfield #14; //Field this$0:LFoo;
5: aload_0
6: aload_2
7: putfield #16; //Field val$user:LUser;
10: aload_0
11: invokespecial #18; //Method java/lang/Object."<init>":()V
14: return

public void run();
Code:
0: aload_0
1: getfield #14; //Field this$0:LFoo;
4: getfield #26; //Field Foo.nameTextField:Ljavax/swing/JTextField;
7: aload_0
8: getfield #16; //Field val$user:LUser;
11: invokeinterface #32, 1; //InterfaceMethod User.getName:()Ljava/lang/String;
16: invokevirtual #38; //Method javax/swing/JTextField.setText:(Ljava/lang/String;)V
19: return

}

这是我的 Foo.java(你的没有编译...)

import javax.swing.JTextField;

public class Foo {

protected JTextField nameTextField;

public void foo(final User user) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
nameTextField.setText(user.getName());
}
});
}
}

关于java - 事件调度线程的“局部变量需要声明为final”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9683356/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com