[java] Java에서 두 정수를 올바르게 비교하는 방법은 무엇입니까?

박스형 기본 정수를 다음과 같은 상수와 비교하면 다음과 같습니다.

Integer a = 4;
if (a < 5)

a 상자가 자동으로 풀리고 비교가 작동합니다.

그러나 두 박스 Integers를 비교할 때 같거나보다 작거나 큰 것을 비교할 때 어떤 일이 발생 합니까?

Integer a = 4;
Integer b = 5;

if (a == b)

위의 코드는 동일한 객체인지 확인하는 결과가됩니까, 아니면 자동 개봉합니까?

이건 어떤가요:

Integer a = 4;
Integer b = 5;

if (a < b)

?



답변

정수, Long 사이의 아니오, ==는 참조 평등 을 확인합니다. 즉

Integer x = ...;
Integer y = ...;

System.out.println(x == y);

이 있는지 확인한다 x그리고 y받는 참조 같은 객체 보다는 동일한 개체.

그래서

Integer x = new Integer(10);
Integer y = new Integer(10);

System.out.println(x == y);

인쇄가 보장됩니다 false. “작은”자동 상자 값을 삽입하면 까다로운 결과가 발생할 수 있습니다.

Integer x = 10;
Integer y = 10;

System.out.println(x == y);

이것은 true복싱 규칙으로 인해 인쇄됩니다 ( JLS 섹션 5.1.7 ). 여전히 사용중인 참조 평등이지만 참조 실제로 동일합니다.

박스형 값 p가 -128에서 127 사이의 정수형 리터럴 (3.10.1)이거나 부울 리터럴 true 또는 false (§3.10.3)이거나 ‘\ u0000’과 ‘\ u007f’포함 (§3.10.4)을 선택한 다음 a와 b를 p의 두 복싱 변환 결과로 설정하십시오. 항상 a == b입니다.

개인적으로 사용합니다 :

if (x.intValue() == y.intValue())

또는

if (x.equals(y))

말로서, 래퍼 타입 (사이의 비교 Integer, Long등) 및 숫자 타입 ( int, long등) 랩퍼 타입 값은 박스 없음 시험이 관련 프리미티브 값에 적용된다.

이진 숫자 승격의 일부로 발생합니다 ( JLS 섹션 5.6.2 ). 각 개별 운영자의 설명서를보고 적용 여부를 확인하십시오. 예를 들어 ==및에 대한 문서에서 !=( JLS 15.21.1 ) :

항등 연산자의 피연산자가 모두 숫자 유형이거나 하나가 숫자 유형이고 다른 하나가 숫자 유형으로 변환 가능한 경우 (§5.1.8) 피연산자에 대해 이진 숫자 승격이 수행됩니다 (§5.6.2).

과에 대한 <, <=, >>=( JLS 15.20.1 )

숫자 비교 연산자의 각 피연산자 유형은 기본 숫자 유형으로 변환 가능한 유형 (§5.1.8)이어야합니다. 그렇지 않으면 컴파일 타임 오류가 발생합니다. 이항 숫자 승격은 피연산자 (§5.6.2)에서 수행됩니다. 피연산자의 승격 된 유형이 int 또는 long이면 부호있는 정수 비교가 수행됩니다. 이 승격 된 유형이 float 또는 double 인 경우 부동 소수점 비교가 수행됩니다.

이 중 어느 것도 어떤 유형도 숫자 유형이 아닌 상황의 일부로 간주 되지 않습니다 .


답변

==여전히 객체 평등을 테스트합니다. 그러나 속이기 쉽습니다.

Integer a = 10;
Integer b = 10;

System.out.println(a == b); //prints true

Integer c = new Integer(10);
Integer d = new Integer(10);

System.out.println(c == d); //prints false

불평등이있는 예제는 개체에 정의되어 있지 않기 때문에 작동합니다. 그러나 ==비교를 통해 객체 동등성이 여전히 검사됩니다. 이 경우, 박스형 프리미티브에서 객체를 초기화하면 동일한 객체가 사용됩니다 (a와 b 모두). 프리미티브 박스 클래스는 불변이므로 최적화입니다.


답변

Java 1.7부터 Objects.equals 를 사용할 수 있습니다 .

java.util.Objects.equals(oneInteger, anotherInteger);

인수가 서로 같으면 true를, 그렇지 않으면 false를 반환합니다. 결과적으로 두 인수가 모두 널이면 true가 리턴되고 정확히 하나의 인수가 널이면 false가 리턴됩니다. 그렇지 않으면, 첫 번째 인수의 equals 메소드를 사용하여 동등성을 판별합니다.


답변

== 그러나 다음과 같은 코드를 작성할 때 참조 평등을 확인합니다.

Integer a = 1;
Integer b = 1;

Java는 aand b에 대해 동일한 불변의 것을 재사용 할 수있을만큼 똑똑 합니다 a == b. 호기심, 나는 자바가 이런 식으로 최적화를 멈추는 곳을 보여주는 작은 예제를 썼다.

public class BoxingLol {
    public static void main(String[] args) {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            Integer a = i;
            Integer b = i;
            if (a != b) {
                System.out.println("Done: " + i);
                System.exit(0);
            }
        }
        System.out.println("Done, all values equal");
    }
}

이것을 컴파일하고 (내 컴퓨터에서) 실행할 때 나는 다음을 얻습니다.

Done: 128


답변

TL은, 박사 내 의견은 단항를 사용하는 것입니다+ 값 평등을 확인할 때 피연산자 중 하나에서 unboxing을 트리거하고 그렇지 않으면 단순히 수학 연산자를 사용하는 것입니다. 근거는 다음과 같습니다.

이미 언급 된 ==에 대한 비교가 Integer프로그래머가 원하는 것을 일반적으로하지 않고, 목표 값의 비교를하는 것입니다 정체성 비교입니다; 그래도 코드 압축, 정확성 및 속도 측면에서 가장 효율적으로 비교를 수행하는 방법에 대해 약간의 과학 을 수행했습니다.

일반적인 방법을 사용했습니다.

public boolean method1() {
    Integer i1 = 7, i2 = 5;
    return i1.equals( i2 );
}

public boolean method2() {
    Integer i1 = 7, i2 = 5;
    return i1.intValue() == i2.intValue();
}

public boolean method3() {
    Integer i1 = 7, i2 = 5;
    return i1.intValue() == i2;
}

public boolean method4() {
    Integer i1 = 7, i2 = 5;
    return i1 == +i2;
}

public boolean method5() { // obviously not what we want..
    Integer i1 = 7, i2 = 5;
    return i1 == i2;
}

컴파일 및 디 컴파일 후이 코드를 얻었습니다.

public boolean method1() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    return var1.equals( var2 );
}

public boolean method2() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    if ( var2.intValue() == var1.intValue() ) {
        return true;
    } else {
        return false;
    }
}

public boolean method3() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    if ( var2.intValue() == var1.intValue() ) {
        return true;
    } else {
        return false;
    }
}

public boolean method4() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    if ( var2.intValue() == var1.intValue() ) {
        return true;
    } else {
        return false;
    }
}

public boolean method5() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    if ( var2 == var1 ) {
        return true;
    } else {
        return false;
    }
}

쉽게 알 수 있듯이, 방법 1은 Integer.equals()(분명히), 방법 2-4를 호출 하면 정확히 동일한 코드가 생성 되고.intValue() 나서 직접 비교합니다. 방법 5는 신원 비교를 트리거하여 잘못된 방법입니다. 값을 비교하십시오.

(예를 들어 JS에서 이미 언급했듯이) equals()오버 헤드가 발생하기 때문에 (필요한 instanceof캐스트와 확인되지 않은 캐스트) HotSpot이 아니기 때문에 방법 2-4는 정확히 동일한 속도로 작동합니다. 캐스트를 최적화 할 가능성이 높습니다 instanceof.

다른 비교 연산자 (예 : </ >) 와 매우 유사합니다. 사용 compareTo()하지 않는 동안 언 박싱을 트리거 하지만 이번에는 HS에 의해 작업을 최적화 할 수 있습니다.intValue() 는 getter 방법 (최적화 후보) 할 수 있습니다.

내 의견으로는, 거의 사용되지 않는 버전 4가 가장 간결한 방법입니다. 모든 노련한 C / Java 개발자는 단항 플러스가 대부분의 경우 int/와 동일하다는 것을 알고 .intValue()있습니다. 일부 사람들에게는 약간의 WTF 순간 이 될 수 있습니다. 평생 동안 단항 더하기를 사용하지 않는 것), 가장 분명하고 가장 의도를 의도적으로 보여줍니다- int피연산자 중 하나의 가치를 원한다는 것을 보여줍니다 . 다른 가치도 개봉해야합니다. 또한 i1 == i2기본 int값에 사용되는 정규 비교 와 가장 유사 합니다.

내 투표는 간다 i1 == +i2& i1 > i2에 대한 스타일의 Integer성능 및 일관성을 이유로 모두 객체. 또한 형식 선언 이외의 것을 변경하지 않고도 코드를 프리미티브로 이식 할 수 있습니다. 명명 된 방법을 사용하는 것은 비판적 인 bigInt.add(10).multiply(-3)스타일 과 비슷한 의미 적 노이즈를 도입하는 것처럼 보입니다 .


답변

부름

if (a == b)

대부분의 경우 작동하지만 항상 작동한다고 보장 할 수는 없으므로 사용하지 마십시오.

이름이 ‘a’와 ‘b’인 경우 두 Integer 클래스가 동일한 지 비교하는 가장 적절한 방법은 다음과 같습니다.

if(a != null && a.equals(b)) {
  System.out.println("They are equal");
}

약간 더 빠른이 방법을 사용할 수도 있습니다.

   if(a != null && b != null && (a.intValue() == b.intValue())) {
      System.out.println("They are equal");
    } 

내 컴퓨터에서 첫 번째 방법을 사용하면 990 억 작업이 47 초, 두 번째 방법을 사용하여 46 초가 걸렸습니다. 차이점을 보려면 수십억 개의 값을 비교해야합니다.

‘a’는 Object이므로 null 일 수 있습니다. 이 방법으로 비교해도 널 포인터 예외는 발생하지 않습니다.

보다 크거나 작은 것을 비교하려면

if (a != null && b!=null) {
    int compareValue = a.compareTo(b);
    if (compareValue > 0) {
        System.out.println("a is greater than b");
    } else if (compareValue < 0) {
        System.out.println("b is greater than a");
    } else {
            System.out.println("a and b are equal");
    }
} else {
    System.out.println("a or b is null, cannot compare");
}


답변

두 정수를 비교하기 위해 항상 equals () 메소드를 사용해야합니다.

==를 사용하여 두 정수를 비교하면 JVM의 내부 최적화로 인해 특정 범위의 정수 값 (정수 -128 ~ 127)에서 작동합니다.

예를 참조하십시오 :

사례 1 :

정수 a = 100; 정수 b = 100;

if (a == b) {
    System.out.println("a and b are equal");
} else {
   System.out.println("a and b are not equal");
}

위의 경우 JVM은 캐시 된 풀에서 a와 b의 값을 사용하고 정수 객체의 동일한 객체 인스턴스 (따라서 메모리 주소)를 반환하며 둘 다 동일합니다. 최적화 JVM 은 특정 범위 값에 대해 수행합니다.

사례 2 : 이 경우 a와 b는 -128에서 127 사이의 범위가 아니기 때문에 같지 않습니다.

정수 a = 220; 정수 b = 220;

if (a == b) {
    System.out.println("a and b are equal");
} else {
   System.out.println("a and b are not equal");
}

적절한 방법:

Integer a = 200;
Integer b = 200;
System.out.println("a == b? " + a.equals(b)); // true

이게 도움이 되길 바란다.