2012-10-04 4 views
1

각 항목의 값이 포함 된지도를 사용하여 목록을 정렬하고 싶습니다.자바 비교기는 최종 변수가 아닌 변수를 사용합니다.

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); 
    } 
}) 

나는 1의 값이 2보다 높은 있기 때문에 순서가 0,2,1되고 싶어요. 그러나 자바는 내가 이것을하게하지 않는다. 다음 오류가 발생합니다. Cannot refer to a non-final variable map inside an inner class defined in a different method

어떻게 그렇게 할 수 있습니까?

+3

왜지도를 최종으로 정의하지 않습니까? –

+0

수정해야하기 때문에. 아니면 수정해도 최종 수 있습니까? –

+1

@OskarKjellin 왜 댓글 대신 대답하지 않습니까? :) –

답변

6

그냥 최종합니다지도가 변경 가능한

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); 
    } 
}) 

, 당신은 아직도 그것을 수정할 수 있습니다.

+0

변명 : –

+0

@DavidGrant 아니 걱정, 당신이 옳았 어;) –

1

Comparator은 익명의 내부 클래스입니다. 내부에서 익명의 내부 클래스가 포함 된 메서드에서 선언 된 로컬 변수 map에 액세스하려고합니다.

로컬 변수가 final 인 경우에만이를 수행 할 수 있다는 제한이 있습니다. 그래서, 할 당신의 mapfinal 변수 :

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

익명의 내부 클래스 (비교자가 하나임)는 final으로 선언 된 로컬 변수 만 참조 할 수 있으므로지도에 액세스하려면 final으로 선언해야합니다.

참고 지도 객체을 수정하지 못하도록하지 않습니다 final로 선언, 당신은 단지 변수 map에 새로운 객체를 할당 할 수 없습니다. 귀하의 경우에는

1

해결책은 간단하다 : final로지도를 표시 :

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

는 당신은 아마 단어 final과 혼동된다. 그것은 당신의지도에서 조작에 당신을 제한하지 않습니다. 그것은 단지 당신이 당신의 경우에는 괜찮은지도에 대한 참조를 변경할 수 없습니다.

이 요구 사항의 이유는 비교기가 익명의 내부 클래스이기 때문입니다. 모든 외부 메소드 변수는 익명 클래스에 복사되므로 외부 메소드에서 변수를 변경하면 충돌이 발생합니다. 이것은 컴파일러가 익명 ​​클래스에서 액세스 한 변수를 final로 표시해야하는 이유입니다.

다른 해결책은 클래스를 분리하여 비교기를 추출하여지도를 인수 생성자로 전송하는 것입니다.

0

분명히 할 수 있습니다. 익명 클래스 대신 명명 된 클래스를 Comparator까지 확장하고 Map 변수를 매개 변수로 전달하십시오. 그래서 같이 :

[0, 2, 1] 

을 또한 IMO, 읽는 코드 청소기를 만드는 :

@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); 
    } 
    } 

이 출력합니다.

관련 문제