1. ホーム

[解決済み】別のメソッドで定義された内部クラス内の非終端変数を参照することはできません。

2022-04-02 21:25:04

質問

編集しました。 タイマーを数回走らせながら、いくつかの変数の値を変更する必要があります。タイマーを繰り返し実行するたびに、値を更新し続ける必要があります。私は値を更新することを妨げるので、値をfinalに設定することはできませんが、私は以下の最初の質問で説明したようなエラーを得ます。

以前は以下のように書いていました。

別のメソッドで定義された内部クラス内の非終端変数を参照できない"というエラーが発生します。

これは、priceというdoubleとpriceObjectというPriceに対して起こっています。なぜこのような問題が発生するのかわかりますか?なぜfinal宣言が必要なのかがわかりません。また、私が何をしようとしているのかがわかれば、この問題を回避するために何をしなければならないのかがわかります。

public static void main(String args[]) {

    int period = 2000;
    int delay = 2000;

    double lastPrice = 0;
    Price priceObject = new Price();
    double price = 0;

    Timer timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
            price = priceObject.getNextPrice(lastPrice);
            System.out.println();
            lastPrice = price;
        }
    }, delay, period);
}

解決方法は?

Javaはtrueをサポートしていません。 クロージャ のような無名クラスを使用していても、( new TimerTask() { ... } は、一種のクロージャのように見えます。

編集 - 以下のコメントをご覧ください。以下は、KeeperOfTheSoulが指摘するように、正しい説明ではありません。

これがうまくいかない理由です。

変数 lastPrice とpriceはmain()メソッド内のローカル変数です。匿名クラスで作成したオブジェクトが main() メソッドが返されます。

このとき main() メソッドが返ると、ローカル変数(例えば lastPriceprice ) はスタックから一掃され、そのため main() が返ります。

しかし、匿名クラスオブジェクトはこれらの変数を参照しています。もし匿名クラスオブジェクトがクリーンアップされた後の変数にアクセスしようとしたら、事態はとんでもないことになります。

を作成することで lastPriceprice final の場合、それらはもう本当の変数ではなく、定数です。そうすると、コンパイラは単に lastPriceprice を無名クラスの定数の値で置き換えることで、存在しない変数にアクセスする問題がなくなります(もちろん、コンパイル時に)。

クロージャをサポートしている他のプログラミング言語では、これらの変数を特別に扱い、メソッドの終了時に破壊されないようにして、クロージャがまだ変数にアクセスできるようにしています。

Ankur: これはできますね。

public static void main(String args[]) {
    int period = 2000;
    int delay = 2000;

    Timer timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {
        // Variables as member variables instead of local variables in main()
        private double lastPrice = 0;
        private Price priceObject = new Price();
        private double price = 0;

        public void run() {
            price = priceObject.getNextPrice(lastPrice);
            System.out.println();
            lastPrice = price;
        }
    }, delay, period);      
}