2010-12-29 10 views
11

以下のコードでは、EditTextからfinalというキーワードを削除すると、私はEditTextオブジェクト(et)を目的地に渡す行(6)でエラーが発生しています...ここでは最終的なキーワードの重要性を知っておく必要があります。 ..最終的なキーワードは何ですか?

final EditText et=(EditText)findViewById(R.id.t); 
     Button b=(Button)findViewById(R.id.b1); 
     b.setOnClickListener(new Button.OnClickListener(){ 
      public void onClick(View v)<br> 
      { 
      Intent on=new Intent(Intent.ACTION_CALL,Uri.parse("tel:"+et.getText())); 
      startActivity(on); 
      } 
     }); 
+0

ドロイド変数をしている:あなたは、あなたのLogcatに持っていた誰がどのようなエラーが、私たちに伝えることができますか? –

+0

その実行時間ではなく、コンパイル時にエラーが発生しました。 "別のメソッドで定義された内部クラスの中で、最終的な変数ではないことを参照できませんでした"これは私が得たものです... –

答えて

15

ここで閉鎖を使用しているためです。これは、インナークラスがインバウンドクラスのコンテキストを使用することを意味します。これを使用するには、変数を変更しないようにfinal宣言する必要があります。

詳しくはhereをご覧ください。

+0

ここの内部クラスは...それはOnClickListenerですか? –

+0

もちろんOnClickListenerを実装する匿名クラスです。 –

+0

よろしくお願いします。ありがとうございました... –

2

finalは、変数etを1回のみ割り当てられるようにします。また、変数のスコープを変更し、onClick visibilityの機能をetに許可します。最後がなければ、etは関数onClick内では見えません。

+0

最終的にどのようにしてonClickに見えるのですか、詳しく教えてください。 –

20

最終的には、変数etは、いつでも再割り当てされずに残ります。つまり、リスナーのような内部クラスは、あらゆる種類の問題を引き起こす可能性のある他のスレッドによって再割り当てされることはないと信じることができます。

finalを使用してメソッドまたはクラス定義を変更することもできます。これは、そのメソッドをサブクラスで上書きできないこと、またはそのクラスを拡張できないことを意味します。

+0

興味深い私は決着がそのような効果のための方法で使用できることを知らなかった。将来のある時点で便利なはずです。 – schwiz

+0

「変数 'et'は再割り当てされません」と言うと、より正確です。 'final'は変数に適用され、参照されるオブジェクトには適用されません。 – barjak

0

Here is a linkについては、finalというキーワードが記載されています。 the specification(セクション4.12.4)によると:

変数は最終的に宣言できます。最終変数は一度にのみ割り当てることができます。割り当ての直前に割り当てられていない(§16)場合を除き、最終変数が割り当てられている場合はコンパイル時エラーです。

3

読むthis articleが関与実装の詳細を理解するために:私たちは、ローカルクラスの実装方法にいくつかの光を当てる 場合

この制限 の理由は明らかになります。 コンパイラ は自動的にクラスに プライベートインスタンスフィールドを与え、クラスが使用する各ローカル変数のコピー を保持するため、匿名ローカルクラスはローカル 変数を使用できます。 コンパイラはまた、 パラメータを各コンストラクタに追加して、 これらの自動的に作成された プライベートフィールドを初期化します。したがって、ローカルクラス はローカル変数 に実際にはアクセスしませんが、それ自身のプライベート のコピーになります。これは が正しく動作する唯一の方法です。 変数がfinal宣言されている場合、 は変更されないことが保証されています。 ローカルクラスでは、 変数の内部コピーが実際のローカル 変数を正確に反映していることが保証されています( )。

EDIT:

ベルリン・ブラウンは言う:「私は 匿名内部クラスの逆コンパイル版を掲載しました。しかし、 正直であるために、私はまだ コンパイラがその情報を持っていなければならない理由は分かりません。 フィールドがfinal宣言されていても、 フィールドはnullのままです。私は これはそれらのJavaの癖の一つだと思う、あなたは そのフィールドを宣言する必要があります 最終...それは方法ですので。 『変数ではなく値を超えるあります。のは、最終的なローカル変数を持つのは要求がなかったと仮定しましょう「理由は、ユーザーがクロージャことを実現していることを確認することです

』なぜ明確な理由はありません。そして、私たちは書くことができ、コードのように:

public void doIt() { 
    for(int i = 0; i < 3; ++i) { 
     runnables.add(new Runnable() { 
      @Override 
      public void run() { 
       System.out.println(i); 
      } 
     }); 
    } 
    run(runnables); // run each runnable 
} 

何が出力されることと思いますあなたはRunnableをは「変数」の上に私を閉じていないので、それが「0 1 2」は、あなたが誤解されるだろうになると思いますか?その時点でのiの「値」となるので、出力は「2 2 2」になります。ここで期待される動作を達成するためにできること2つの解決策:ユーザーをh閉鎖の仕組みを理解したり、何らかの形でそれを言語レベルで実施したりすることができます。そして、それは言語設計者が行った第2の選択肢です。

public void doIt() { 
    for(int i = 0; i < 3; ++i) { 
     final int j = i; // notice the final local variable 
     runnables.add(new Runnable() { 
      @Override 
      public void run() { 
       System.out.println(j); 
      } 
     }); 
    } 
    run(runnables); 
} 

JFTR、私はそれが匿名内部クラスで使用される前に、最終的なとしてマークされ、ローカル変数を持つことが、私にとって大したブレーカであることだけだ、目のオプションはどこへ行く「」方法であるとは言いませんよ。もちろん、YMMV。 :-)

+0

私は匿名の内部クラスの逆コンパイルされたバージョンを投稿しました。しかし、正直言って、私はまだコンパイラがその情報を持っていなければならない理由は分かりません。フィールドがfinal宣言されても、フィールドはnullのままです。私はこれがJavaの奇妙なものの一つだと思います。あなたはそのフィールドを最終的に宣言しなければなりません。理由は明確ではありません。 –

+0

@Berlin Brown:あなたの懸念に対処するために答えを更新しました。 –

0

また、Javaが匿名の内部クラスを作成する方法を理解するのにも役立ちます。 Javaがその特定のクラスをどのように実装するか。

Javaはコンパイラがコンパイル時にそのオブジェクトの型を知っていなければならないため、その変数をfinalにする必要があります。コンパイラは、匿名内部クラスの実装(この場合は 'et')内にフィールドを生成します。

タイプがfinalでない場合、コンパイラーはどのように内部クラスの実装を構築するかを決定します。基本的に、フィールドfinalを宣言することにより、Javaコンパイラに詳細情報を提供します。コンパイラを助けない

コード、あなたの匿名の内部クラスをコンパイルしません。

Object et; 
et = a ? new Object() : new EditText(); 

...

を上記のコードでは、Javaコンパイラは、実際に構築することはできません匿名の内部クラス。

あなたコード:

最終のEditTextら=(のEditText)findViewById(R.id.t)。

...

new Button.OnClickListener$1(){ 
      public void onClick(View v)<br> 
      { 
      Intent on=new Intent(Intent.ACTION_CALL,Uri.parse("tel:"+et.getText())); 
      startActivity(on); 
      } 
     }); 

... Javaコンパイラは、あなたがそれは次のようになります。但し、内部クラスブロックの実装をバイトコードクラスを作成します。

public class OnClickListener$1 { 

private final EditText et ; <---- this is important 
public OnClickListener$1(final et) { 
    this.et = et; 
} 
public void onClick(View v)<br> 
       { 
       Intent on=new Intent(Intent.ACTION_CALL,Uri.parse("tel:"+et.getText())); 
       startActivity(on); 
       } 
} 

あなたは私が匿名のバイトコードクラスに$ 1見つけることによって、そのバイトコードファイル逆コンパイル提供擬似コードをテストすることができます。

1

JAVAで「最後の」キーワードは3つのレベルで定義することができるの目的は、クラス、メソッド、

Java final variable: If you make any variable as final, you cannot change the value of final variable (It will be constant). 

Java final method: If you make any method as final, you cannot override it. 

Java final class: If you make any class as final, you cannot extend it. 
関連する問題