2

各項目の値を含むマップを使用して、リストを並べ替えたいと思います。

Map<Integer, Float> map = new HashMap<>();
List<Integer> list = new ArrayList<>();

map.put(0, 0.0f);
map.put(1, 5.0f);
map.put(2, 2.0f);

list = new ArrayList<>(map.keySet());

Collections.sort(list, new Comparator<Integer>() {
    public int compare(Integer left, Integer right) {
        Float leftCost = map.get(left);
        Float rightCost = map.get(right);
        return leftCost.compareTo(rightCost);
    }
})

0,2,1の値1が よりも高いため、順序を にしたい2。しかし、Javaは私にこれをさせません。次のエラーが表示されます。Cannot refer to a non-final variable map inside an inner class defined in a different method

どうすればそのような方法でこれを行うことができますか?

4

5 に答える 5

7

最終的にするだけです:

final Map<Integer, Float> map = new HashMap<Integer, Float>();
List<Integer> list = new ArrayList<Integer>(); // this assignment is unncessary [1]

map.put(0, 0.0f);
map.put(1, 5.0f);
map.put(2, 2.0f);

list = new ArrayList<Integer>(map.keySet()); // 1. assignment is replaced here

Collections.sort(list, new Comparator<Integer>() {
    public int compare(Integer left, Integer right) {
        Float leftCost = map.get(left);
        Float rightCost = map.get(right);
        return leftCost.compareTo(rightCost);
    }
})

マップは可変であるため、引き続き変更できます。

于 2012-10-04T12:31:10.917 に答える
3

匿名の内部クラス (コンパレーターは 1 つ) はfinal、マップにアクセスするために、宣言されているローカル変数のみを参照できます - として宣言する必要がありますfinal

として宣言してもfinal、マップ オブジェクトを変更できなくなるわけではありません。新しいオブジェクトを変数に割り当てることはできませんmap

于 2012-10-04T12:31:18.740 に答える
1

あなたComparatorは匿名の内部クラスです。mapその中で、匿名内部クラスを含むメソッドで宣言されたローカル変数 にアクセスしようとしています。

Java には、ローカル変数が の場合にのみこれを実行できるという制限がありますfinal。したがって、変数を作成しますmap final

final Map<Integer, Float> map = new HashMap<>();
于 2012-10-04T12:30:55.277 に答える
1

あなたの場合、解決策は簡単です:マップを次のようにマークしますfinal:

final Map<Integer, Float> map = new HashMap<>();

あなたはおそらく単語と混同されていますfinal。マップの操作を制限しません。あなたの場合は問題ないマップへの参照を変更することはできません。

この要件の理由は、コンパレータが匿名の内部クラスであるためです。すべての外部メソッド変数は匿名クラスにコピーされるため、外部メソッドでそれらを変更すると競合が発生します。これが、匿名クラスからアクセスされる変数を final としてコンパイラがマークする必要がある理由です。

他の解決策は、コンパレータを抽出してクラスを分離し、マップを引数コンストラクタとして送信することです。

于 2012-10-04T12:34:05.473 に答える
0

あなたは間違いなくこれを行うことができます。拡張する匿名クラスの代わりに名前付きクラスを作成し、変数をパラメーターとしてComparator渡すだけです。Mapそのようです:

  @Test
  public void test() {
    Map<Integer, Float> map = new HashMap<Integer, Float>();
    map.put(0, 0.0f);
    map.put(1, 5.0f);
    map.put(2, 2.0f);

    List<Integer> list = new ArrayList<Integer>(map.keySet());
    Collections.sort(list, new FloatComparator(map));

    System.out.println(list);
  }

  class FloatComparator implements Comparator<Integer> {
    private Map<Integer, Float> mapRef;
    public FloatComparator(Map<Integer, Float> newMap) {
      mapRef = newMap;
    }

    @Override
    public int compare(Integer left, Integer right) {
      Float leftCost = mapRef.get(left);
      Float rightCost = mapRef.get(right);
      return leftCost.compareTo(rightCost);
    }
  }

これは出力します:

[0, 2, 1]

また、コードを読みやすくします、IMO。

于 2012-10-04T12:51:04.007 に答える