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

匿名内部类(您的比较器是一个)只能引用已声明的局部变量,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<>();

您可能对 word 感到困惑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 回答