2012-03-13 18 views
0

イベントディスパッチスレッドを使用してさまざまなスイングコンポーネントを更新しています。私は、次のような何かをするときしかし、私はエラーを取得する -イベントディスパッチスレッドで 'ローカル変数を最終宣言する必要があります'

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

誤りがある - 「ローカル変数ユーザーが内部クラス内からアクセスされ、最終的に宣言する必要があり、」

を標準溶液である何これに...各関数のパラメータの前にfinalを置くだけですか?

私の実際のユーザオブジェクトは、今後変更する必要があるため、最終的には宣言したくありません。しかし、関数のパラメータでユーザーオブジェクトのfinalを設定するだけでいいですか?

しかし、これを私のプログラムの「メイン」ユーザオブジェクトへの参照として、最終的に設定すると、実際に何をしていますか?したがって、同じオブジェクトはある場所で最終的に宣言されますが、別の場所では最終的なものではありません。それを最終的に宣言すれば、それへの参照は最終的ですが、ユーザーオブジェクト自体は自由に変更できますか?

答えて

4

解決策は、提案するように関数の引数を最終的にすることです。

最終変更子は、最初の割り当て後に参照を再割り当てできないことを意味します。それは参照されるオブジェクトに保証を与えません。

btwこれは、匿名の内部クラスが言語に「埋め込まれた」方法の人為的なものです。コンパイラは各引数の隠しフィールドを作成します。上のコードを逆コンパイルすると、何が起こっているのかを見ることができます。

以下の逆コンパイルでは、新しいクラスFoo $ 1が作成されています(fooメソッド#0) 6行目ではコンストラクタのUser argが渡されます。あなたは、同様のペテンは$ 1.class

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" より作成 "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の逆コンパイルで起こって表示されます

ここに私の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()); 
      } 
     }); 
    } 
} 
2

これに対する標準的な解決策は何ですか...各関数パラメータの前にfinalを置くだけですか?

はい

しかし、私は最終的にそれは私のプログラムの「メイン」ユーザオブジェクトへの参照であるとことを設定したときに、私は実際にやっています。したがって、同じオブジェクトはある場所で最終的に宣言されますが、別の場所では最終的なものではありません。それを最終的に宣言すれば、それへの参照は最終的ですが、ユーザーオブジェクト自体は自由に変更できますか?

はい。個々のオブジェクトは、final、変数(プリミティブまたは参照)、クラスおよびメソッドのみにすることはできません。

2

私はローカル変数を使用して、最も単純な方法

1)

public Foo(User user) { 

    final String /*(Object, int ....whatever)*/ str = user.getName(); 

    java.awt.EventQueue.invokeLater(new Runnable() { 
     public void run() { 
      getNameTextField.setText(str); 
     } 
    }); 
} 

2)について話しているが

1

これまでの標準的なソリューションは、あなたがあなたの変数を作成する必要がありますfinal ..

inner class need **user** to be final.. Because of , 
avoid strange side-effects with closures in java variables referenced by an anonymous 
delegate must be marked as final.. 

これを行う最善の方法は..

public Foo(User user) { 
final User user_final=user; 
java.awt.EventQueue.invokeLater(new Runnable() { 
    public void run() { 
     getNameTextField.setText(user_final.getName()); 
    } 
}); 
} 
関連する問題