0

私はこのコードを持っています:

public void onPlayerInteract(PlayerInteractEvent event) {
    final Action action = event.getAction();
    Location l1 = null;
    Location l2 = null;
    if (action == Action.LEFT_CLICK_BLOCK){
        l1 = event.getClickedBlock().getLocation();
    } else if (action == Action.RIGHT_CLICK_BLOCK) {
        l2 = event.getClickedBlock().getLocation();
    }

    Thread t = new Thread() {
        @Override
        public void run() {
            while(true) {
                try {
                    Thread.sleep(1000*60*60);
                    Location maxx = l1.getX();
                    Location maxy = l1.getY();
                    Location maxz = l1.getZ();

                    Location minx = l2.getX();
                    Location miny = l2.getY();
                    Location minz = l2.getZ();

                    if(l1.getX() > l2.getX()){
                        //I can't execute this, errors!
                    }
                } catch (InterruptedException ie) {
                }
            }
        }
    };
    t.start();

エラーが発生し、l1とl2をファイナルに変更するように指示されます。l1とl2をファイナルに変更すると、別のエラーが発生し、l1 =などと表示され、ファイナルを削除するように指示されます。

4

5 に答える 5

7

l1およびl2メソッドのローカル変数ですonPlayerInteract()。このメソッドでは、これらのローカル変数l1とを使用する匿名内部クラスを作成しますl2。これは、l1l2が最終的な場合にのみ可能です。ただし、定義上、final 変数は 1 回しか割り当てられず、null を割り当ててから別の値を割り当てます。したがって、最終変数のコピーを作成し、それらの最終コピーを匿名クラス内で使用する必要がありl1ますl2

public void onPlayerInteract(PlayerInteractEvent event) {
    final Action action = event.getAction();
    Location l1 = null;
    Location l2 = null;
    if (action == Action.LEFT_CLICK_BLOCK){
        l1 = event.getClickedBlock().getLocation();
    } else if (action == Action.RIGHT_CLICK_BLOCK) {
        l2 = event.getClickedBlock().getLocation();
    }

    final Location l1Final = l1;
    final Location l2Final = l2;

    Thread t = new Thread() {
        @Override
        public void run() {
            while(true) {
                try {
                    Thread.sleep(1000*60*60);
                    Location maxx = l1Final.getX();
                    Location maxy = l1Final.getY();
                    Location maxz = l1Final.getZ();

                    Location minx = l2Final.getX();
                    Location miny = l2Final.getY();
                    Location minz = l2Final.getZ();


                    if(l1Final.getX() > l2Final.getX()){
                        // ...
                    }
                } catch (InterruptedException ie) {
                }
            }
        }
    };
    ...
}
于 2012-05-25T22:46:00.430 に答える
1

匿名内部クラスにはfinalを使用する必要があります。ご存知かもしれませんが、最終的な参照は変更できません。

JBNizetの答えは正しいです。

ただし、JBNizetコードの代わりに次のことに注意してください。

Location l1 = null;
Location l2 = null;
if (action == Action.LEFT_CLICK_BLOCK){
    l1 = event.getClickedBlock().getLocation();
} else if (action == Action.RIGHT_CLICK_BLOCK) {
    l2 = event.getClickedBlock().getLocation();
}

final Location l1Final = l1;
final Location l2Final = l2;

次のコードを使用できます

final Location l1;
final Location l2;
if (action == Action.LEFT_CLICK_BLOCK){
    l1 = event.getClickedBlock().getLocation();
    l2 = null;
} else if (action == Action.RIGHT_CLICK_BLOCK) {
    l1 = null;
    l2 = event.getClickedBlock().getLocation();
} else {
    l1 = null;
    l2 = null;
}

ローカル変数は(nullにさえ)初期化されないため、コンパイラーは、使用する前に初期化するように指示することがよくあります。ただし、if / elseif / else構造体のすべての場合に初期化すると、コンパイラーは、どのような場合でも初期化したことを確認します。

とにかく、いずれの場合もl1またはl2がnullになるため、コードは意味をなさないようです。したがって、スレッドは常にNullPointerExceptionをスローします。


匿名内部クラスにfinalを使用する必要がある理由の説明は次のとおりです 。匿名内部クラスでfinalキーワードを使用するのはなぜですか。


また、ステートメントif(l1.getX()> l2.getX()){getX()とgetY()はLocationを返し、>演算子を使用して比較できないため、ステートメントを使用できないことに注意してください。LocationクラスでComparableの使用を検討してから、if(l1.getX()。compareTo(l2.getX())> 0){...}を実行する必要があります。

于 2012-05-25T23:18:44.370 に答える
1
public void onPlayerInteract(PlayerInteractEvent event) {
    final Action action = event.getAction();
    final Location blockLocation = event.getClickedBlock().getLocation();
    final Location l1 = (action == Action.LEFT_CLICK_BLOCK) ? blockLocation : null;
    final Location l2 = (action == Action.RIGHT_CLICK_BLOCK) ? blockLocation : null;

    Thread t = new Thread() {
        ...
    }
}
于 2012-05-25T22:43:21.410 に答える
0

解決策は@JB Nizetによって説明されていますが、セッターメソッドがある場合は変数をコピーする必要はありません。コードは次のようになります (@ で説明されているように null ポインターも修正します)。

public void onPlayerInteract(PlayerInteractEvent event) {
final Action action = event.getAction();
final Location l1 = new Location(); // Assumming Location has a default constructor.
final Location l2 = new Location();
if (action == Action.LEFT_CLICK_BLOCK){
    l1.setX(event.getClickedBlock().getLocation().getX());
    l1.setY(event.getClickedBlock().getLocation().getY());
} else if (action == Action.RIGHT_CLICK_BLOCK) {
    l2.setX(event.getClickedBlock().getLocation().getX());
    l2.setY(event.getClickedBlock().getLocation().getY());
}

Thread t = new Thread() {
    @Override
    public void run() {
        while(true) {
            try {
                Thread.sleep(1000*60*60);
                Location maxx = l1Final.getX();
                Location maxy = l1Final.getY();
                Location maxz = l1Final.getZ();

                Location minx = l2Final.getX();
                Location miny = l2Final.getY();
                Location minz = l2Final.getZ();


                if(l1.getX() > l2.getX()){
                    // ...
                }
            } catch (InterruptedException ie) {
            }
        }
    }
};
...

}

@Kkkev asnwer も正常に動作するはずですが、null ポインターに注意してください。

于 2012-05-25T23:06:35.793 に答える
0

run 内のコードは、実質的に独自のメソッドです。別の実行可能なメソッドにして、インスタンス化時に y1 & y2 を渡すか、実行内で y1 & y2 を宣言することができます。

于 2012-05-25T22:50:23.420 に答える