2014-04-19 4 views
1

HashMap에서 사용하려는 사용자 정의 클래스 MarioState가 있습니다. 클래스는 마리오 게임의 상태 공간에서 가능한 상태를 나타냅니다. 다음은 MarioState 클래스의 단순화 된 버전입니다.HashMap의 ContainsKey가 사용자 정의 클래스와 함께 키로 작동하지 않습니다.

내 HashMap에서이 상태를 저장하고 싶습니다. 그러나 MarioState의 재산은 두 개의 MarioState를 비교할 때 고려해야 할 사항입니다. 예를 들어 하나의 MarioState가 true로 설정된 30 개의 거리와 다른 MarioState의 stuck 속성이 true이지만 다른 거리 값 (예 : 20)으로 설정된 경우 동일한 MarioState가 여전히 동일하게 간주되어야합니다.

내 HashMap에서 작동하도록 알고있다. (내가 InteliJ IDE에서 자동으로 생성하도록함으로써) .equals() 및 .hashcode() 메소드를 구현해야한다. 그것은 그들의에 따라하지 말아야 할 때

공용 클래스 MarioState {

// Tracking the distance Mario has moved. 
private int distance; 
private int lastDistance; 

// To keep track of if Mario is stuck or not. 
private int stuckCount; 
private boolean stuck; 

public MarioState(){ 
    stuckCount = 0; 
    stuck = false; 

    distance = 0; 
    lastDistance = 0; 
} 

public void update(Environment environment){ 

    // Computing the distance 
    int tempDistance = environment.getEvaluationInfo().distancePassedPhys; 
    distance = tempDistance - lastDistance; 
    lastDistance = tempDistance; 

    // If Mario hasn't moved for over 25 turns then this means he is stuck. 
    if(distance == 0){ 
     stuckCount++; 
    } else { 
     stuckCount = 0; 
     stuck = false; 
    } 

    if(stuckCount > 25){ stuck = true; } 
} 

public float calculateReward(){ 
    float reward = 0f; 
    reward += distance * 2; 
    if(stuck){ reward += -20; } 
    return reward; 
} 

@Override 
public boolean equals(Object o) { 
    if (this == o) return true; 
    if (o == null || getClass() != o.getClass()) return false; 

    MarioState that = (MarioState) o; 

    if (stuck != that.stuck) return false; 

    return true; 
} 

@Override 
public int hashCode() { 
    return (stuck ? 1 : 0); 
} 

은}

문제는 코드를 실행할 때 키 중 일부는 다른 간주됩니다 그러나입니다. equals() 및 .hashcode() 함수를 호출합니다. 무엇이 이것을 일으킬 수 있습니까? 내가 뭔가 잊었 니?

HashMap의에서 상태를 삽입 할 때 사용되는 코드 (필요한 경우 추가 정보를 제공 할 수있다),

public float[] getActionsQValues(MarioState state){ 
    if(!table.containsKey(state)) { 
     float[] initialQvalues = getInitialQvalues(state); 
     table.put(state, initialQvalues); 
     return initialQvalues; 
    } 
    return table.get(state); 
} 

스크린 샷을 내가 디버그 모드에있어 서로 다른 값을 가진 두 개의 키가 포함 된 내 테이블을 표시하지만 키 자체는 동일합니다 (그러나 HashMap에서는 다른 것으로 간주됩니다).

Screenshot of Debug Mode

+3

지도에 요소를 추가 한 후에'stuck' *을 변경 하시겠습니까? 그것은 분명히 그것을 설명 할 것입니다. –

+0

@JonSkeet 짧은 답변 : 예. 답변 : 현재 상태를 변수로 추적하는 다른 클래스가 있습니다. MarioState에서 업데이트 메소드를 호출하고 상태가 변경되면 수정하는 모든 시간 단계. 그런 다음, 수정 된 상태를 HashMap의 상태로 검사하는 getActionsQValues가 호출됩니다. 상태가 HashMap에 완전히 새로운 경우 (즉, HashMap에 아직 생성되지 않은 속성의 고유 한 조합) 만 입력해야합니다. –

+1

짧은 대답 : 키의 해시 코드가 추가 된 후에 변경되지 않는다는 HashMap 가정이 깨졌습니다. 키가있는지도를 갖는 것이 매우 이상합니다. 어쨌든 단일 '부울'값은 정직합니다. –

답변

2

는 귀하의 해시 코드의 계산과 동등 비교는 모두 stuck을 기반으로 -하지만 시간이 지남에 따라 변경 될 수 있습니다.

개체를 해시 맵 내에서 키로 추가 한 후에이를 변형하면 해시 코드가 변경되는 방식으로 해당 개체를 나중에 요청할 때 키를 찾을 수 없습니다. 저장된 해시 코드 키가 처음 추가되었을 때 현재의 해시 코드와 더 이상 동일하지 않습니다.

가능한 경우 변경 가능한 객체를지도 내의 키로 사용하지 마십시오. 해시 코드를 사용하지 않는 TreeMap도 상대적인 순서가 변경되는 방식으로 객체를 변경 한 경우 동일한 문제가 발생합니다. 수정 가능한 객체를지도 내의 키로 사용해야하는 경우 키로 추가 한 후에는 변경해서는 안됩니다.

+0

정보 및 팁 주셔서 감사합니다! 나는 불변의 객체를 대신 키로 사용할 수 있는지 (또는 변형시키는 것을 방지 할 수 있는지) 살펴볼 것입니다. –

관련 문제