2017-09-01 11 views
1

私は、ローカル・インナー・クラスが外部メソッドから変数にアクセスする方法についての「コアJava」の本を学んでいます。一方、私は何かについて混乱しています。メソッドはまだ終了していませんが、ローカル変数はもう存在しません。

本は、ここでのコードのスニペットを提供する:

  1. startメソッドが呼び出される:

    public void start(int interval, boolean beep) 
    { 
        class TimePrinter implements ActionListener 
        { 
         public void actionPerformed(ActionEvent event) 
         { 
          System.out.println("At the tone, the time is " + new Date()); 
          if (beep) Toolkit.getDefaultToolkit().beep(); 
         } 
        } 
    
        ActionListener listener = new TimePrinter(); 
        Timer t = new Timer(interval, listener); 
        t.start(); 
    } 
    

    本がどのように制御フローこことして示しています。

  2. listenerが初期化されます。
  3. listenerの参照は、Timerコンストラクタに渡されます。 この時点でstartメソッドのパラメータ変数beepは存在しなくなりました。
  4. 瞬間後に、actionPerformed方法はif (beep) ...

私はビープ音がもはや存在しない理由についてだけで混乱していますを実行しますか?私は、コンパイラがbeep効果的に最終であるため、変更しないと仮定することができることを知っている

+2

したがって、メソッド内でクラスを宣言していますか?私はこれが最初にコンパイルされることを非常に疑う。 – Stultuske

+1

@Stultuske eclipseはそのトピックについて何もエラーを投げません – XtremeBaumer

+1

ローカル・クラスと呼ばれます。[この例](https://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html)を参照してください。コンパイルは成功です。 – DevDio

答えて

1

これは本の正確な引用である場合、本は間違っています。 start関数のbeepパラメータが、閉じ括弧}まで範囲外にならないことは間違いありません。ローカルクラスの使用によって引き起こされる特別な動作はありません。このシナリオでは


、変数は"captured"ていたと言われています。

変数を取得するには、final or "effectively final"のいずれかを指定する必要があります。つまり、変数を決して再割り当てしないでください。

beepの値を変更しないでください。実際には最終的にキャプチャされるようになります。

TimePrinterオブジェクトを作成すると、値beepが内部状態にコピーされます。これは、変数beepが使用する必要がある時間までに範囲外になった可能性があるためです。

タイマーが開始され、startメソッドが終了します。元のbeepが現在範囲外になりました。数秒ごとに(intervalに応じて)actionPerformedが呼び出されます。元のbeepになりましたが、その値のコピーを作成して、私たちの機能がまだ期待通りに実行できるようにしました。

これは、作者が表現しようとしている考えです。

+0

ありがとう、私はあなたがポイントを得ると思います。 –

2

...ローカル変数はまだ住むことができる、}外側のstartメソッドは、まだ終わりに近づいていないと思いました。その後のようなものとして、ローカルオブジェクトを構築するために手配します:beepパラメータは、それは変わらない。すなわち、効果的に最終であっても壊すことなくfinal beepを宣言することができれば

class TimePrinter implements ActionListener { 
     // Capture the local variable in this instance. 
     boolean instanceBeep = beep; 
     public void actionPerformed(ActionEvent event) { 
      System.out.println("At the tone, the time is " + new Date()); 
      if (instanceBeep) Toolkit.getDefaultToolkit().beep(); 
     } 
    } 

しかし、これはのみ動作しますコード。

public void start(int interval, boolean beep) { 
    class TimePrinter implements ActionListener { 
     public void actionPerformed(ActionEvent event) { 
      System.out.println("At the tone, the time is " + new Date()); 
      // Error:(17, 21) java: local variables referenced from an inner class must be final or effectively final 
      if (beep) Toolkit.getDefaultToolkit().beep(); 
     } 
    } 
    // Add this to see the compiler working it out. 
    beep = false; 
    ActionListener listener = new TimePrinter(); 
    Timer t = new Timer(interval, listener); 
    t.start(); 
} 

と、それはもはや効果的に最終的なものであるためbeepパラメータへのアクセスは、現在許可されていないことがわかりません。

だけのようなものを試してみてください、確認してください。

effectively finalまたはspecのオフィシャルオラクルのドキュメントを参照してください。

+1

@マイケル - 合意 - 修正。 – OldCurmudgeon

+0

詳細をお寄せいただきありがとうございます! –

関連する問題