Long.valueOf(0).equals(Integer.valueOf(0)) 가 거짓인 이유는 무엇입니까?

StackOverflow https://stackoverflow.com/questions/445990

  •  22-07-2019
  •  | 
  •  

문제

이 질문은 이상한 HashMap.put() 동작

왜인지 알 것 같아 Map<K,V>.put 소요 K 하지만 Map<K,V>.get 소요 Object, 그렇게 하지 않으면 기존 코드가 너무 많이 손상될 것 같습니다.

이제 오류가 발생하기 쉬운 시나리오에 들어갑니다.

java.util.HashMap<Long, String> m = new java.util.HashMap<Long, String>();
m.put(5L,"Five"); // compiler barfs on m.put(5, "Five")
m.contains(5); // no complains from compiler, but returns false

true를 반환하여 이 문제를 해결할 수 없었나요? Long 가치는 이내였다 int 범위와 값이 동일합니까?

도움이 되었습니까?

해결책

다음은 Long.java의 소스입니다

public boolean equals(Object obj) {
    if (obj instanceof Long) {
        return value == ((Long)obj).longValue();
    }
    return false;
}

즉, 동일하려면 긴 유형이어야합니다. 나는 다음 사이의 주요 차이점이라고 생각합니다.

long l = 42L
int i = 42;
l == i

위의 예는 프리미티브를 사용하면 int 값의 암시 적 확대가 발생할 수 있지만 객체 유형에는 Integer에서 Long으로 암시 적으로 변환하는 규칙이 없다는 것입니다.

또한 체크 아웃하십시오 자바 퍼즐 러, 그것은 이와 비슷한 많은 예가 있습니다.

다른 팁

일반적으로 계약에 엄격하게 표현되지는 않지만 equals (), 객체는 자신을 동일한 클래스가 아닌 다른 객체와 동일하게 간주해서는 안됩니다 (하위 클래스이더라도). 대칭 속성을 고려하십시오 - a.equals (b)가 참이면 B.equals (a)도 참이어야합니다.

두 개의 물체를 가지고합시다. foo 수업의 Super, 그리고 bar 수업의 Sub, 확장됩니다 Super. 이제 구현을 고려하십시오 equals() Super, 특히 AS라고 불리는 경우 foo.equals(bar). Foo는 바가 Object, 정확한 비교를 얻으려면 SUPER의 인스턴스이며 거짓을 반환하지 않으면 확인해야합니다. 이 부분은 괜찮습니다. 이제 모든 인스턴스 필드 등 (또는 실제 비교 구현이 무엇이든)를 비교하고 동일하게 찾습니다. 여태까지는 그런대로 잘됐다.

그러나 계약에 따라 Bar.equals (FOO)도 True를 반환 할 것임을 알고있는 경우에만 사실을 반환 할 수 있습니다. Bar는 Super의 서브 클래스가 될 수 있으므로 equals () 메소드가 재정의 될지 여부는 확실하지 않습니다 (아마도 아마도). 따라서 구현이 올바른지 확인하려면 대칭 적으로 작성하고 두 객체가 동일한 클래스인지 확인해야합니다.

보다 기본적으로, 다른 클래스의 객체는 실제로 동등한 것으로 간주 될 수 없습니다.이 경우 그중 하나만 삽입 할 수 있기 때문입니다. HashSet<Sub>, 예를 들어.

예, 하지만 모든 것은 비교 알고리즘과 변환을 어느 정도까지 수행할 것인지에 달려 있습니다.예를 들어, 당신이 시도할 때 무슨 일이 일어나길 바라나요? m.Contains("5")?아니면 첫 번째 요소로 5가 포함된 배열을 전달한다면?간단히 말하면 "종류가 다르면 키도 다르다"고 연결되어 있는 것 같습니다.

그런 다음 object 열쇠로.당신이라면 무슨 일이 일어나길 바라나요? put5L, 그런 다음 5, "5", ...?만약 당신이 put5L 그리고 5 그리고 "5" 그리고 당신은 5F?

이는 일반 컬렉션(또는 템플릿 또는 원하는 이름)이므로 특정 값 유형을 확인하고 특별한 비교를 수행해야 합니다.K가 int 그런 다음 전달된 객체가 다음과 같은지 확인하세요. long, short, float, double, ...을 선택한 다음 변환하고 비교합니다.K가 float 그런 다음 전달된 객체가 다음과 같은지 확인하세요.

당신은 요점을 이해합니다.

그러나 유형이 일치하지 않으면 예외를 발생시키는 또 다른 구현이 있을 수 있으며, 나는 종종 그렇게 되기를 바랐습니다.

귀하의 질문은 그 얼굴에 합리적으로 보이지만 계약이 아닌 경우, 두 가지 다른 유형에 대해 True를 반환하는 것은 Equals ()에 대한 일반 규칙을 위반하는 것입니다.

Java 언어 디자인의 일부는 객체가 C ++와 달리 다른 유형으로 암시 적으로 변환하지 않는 것이 었습니다. 이것은 Java를 작고 간단한 언어로 만드는 것의 일부였습니다. C ++의 복잡성의 합리적인 부분은 암시 적 변환과 다른 기능과의 상호 작용에서 비롯됩니다.

또한 Java는 프리미티브와 물체 사이에 날카 롭고 눈에 띄는 이분법을 가지고 있습니다. 이것은이 차이가 커버에서 최적화로 숨겨져있는 다른 언어와 다릅니다. 이것은 당신이 길고 정수가 길고 int처럼 행동 할 것을 기대할 수 없다는 것을 의미합니다.

이러한 차이점을 숨기기 위해 라이브러리 코드를 작성할 수 있지만 프로그래밍 환경을 덜 일관성있게 만들어서 실제로 해를 끼칠 수 있습니다.

그래서 코드는 ....

java.util.HashMap<Long, String> m = new java.util.HashMap<Long, String>();
m.put(5L, "Five"); // compiler barfs on m.put(5, "Five")
System.out.println(m.containsKey(5L)); // true

Java가 코드를 자극하고 있다는 것을 잊고 있으므로 위의 코드는 동일합니다.

java.util.HashMap<Long, String> m = new java.util.HashMap<Long, String>();
m.put(new Long(5L), "Five"); // compiler barfs on m.put(5, "Five")
System.out.println(m.containsKey(new Long(5))); // true
System.out.println(m.containsKey(new Long(5L))); // true

따라서 문제의 일부는 오토 옥싱입니다. 다른 부분은 다른 포스터가 언급 한 것과 다른 유형을 가지고 있다는 것입니다.

다른 답변은 실패 이유를 적절하게 설명하지만, 그 중 어느 것도 이 문제와 관련하여 오류가 발생하기 쉬운 코드를 작성하는 방법을 다루지 않습니다.유형 캐스트(컴파일러 도움말 없음), 접미사 기본 형식을 L 등으로 추가하는 것을 기억해야 하는 것은 IMHO에서 허용되지 않습니다.

프리미티브가 있는 경우(그리고 다른 많은 경우에도) GNU 컬렉션 라이브러리를 사용하는 것이 좋습니다.예를 들어, 기본 long으로 내부적으로 항목을 저장하는 TLongLongHashMap이 있습니다.결과적으로, 박싱/언박싱으로 끝나지 않으며 예상치 못한 동작으로 끝나지 않습니다.

TLongLongHashMap map = new TLongLongHashMap();
map.put(1L, 45L);
map.containsKey(1); // returns true, 1 gets promoted to long from int by compiler
int x = map.get(1); // Helpful compiler error. x is not a long
int x = (int)map.get(1); // OK. cast reassures compiler that you know
long x = map.get(1); // Better.

등등.올바른 유형을 얻을 필요는 없으며, 어리석은 일을 하면(int에 long을 저장하려고 시도하는 경우) 컴파일러는 오류(수정하거나 재정의할 수 있음)를 제공합니다.

자동 캐스팅 규칙은 비교도 제대로 작동함을 의미합니다.

if(map.get(1) == 45) // 1 promoted to long, 45 promoted to long...all is well

보너스로 메모리 오버헤드와 런타임 성능이 훨씬 좋아졌습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top