2016-07-07 2 views
3

비교할 데이터가 있습니다. 다른 데이터 유형과 값을 비교해야 할 수도 있습니다. 기본적으로 발생하는 것은 다음과 같습니다.Java : 동일한 값을 가진 두 개의 다른 유형의 객체를 비교하여 true를 반환합니다.

Object a = (long) 1; 
Object b = (int) 1; 


System.out.println(Objects.equals(a, b)); //returns false 

Sysout.out.println(Objects.equals(a.toString(), b.toString())); //returns true 

.toString()을 사용하는 것이 가능한 솔루션처럼 보입니까? 아니면 다른 길로 가야합니까?

편집 :

이 프로그램은 HIVE의 일부 테이블이에 동일한 데이터가있을 수 있습니다 테이블,하지만 서로 다른 데이터 유형에서 읽고 있습니다. 데이터 유형에는 int, smallint, bigint, string, array, double, timestamp가 있습니다.

배열을 보유 할 수있는 배열 유형 외에는 아무것도 없기 때문에 배열 비교와 관련이 없습니다. 그러나 문자열 유형을 타임 스탬프와 비교할 수 있습니다. 나는 또한 비교 결과를 false로해야하기 때문에 int를 두 번 비교하는 것에 관심이 없다.

소수점이없고 다른 데이터 유형이있는 숫자 값은 값과 비교되어야하며 데이터 유형 불일치는 false를 반환하지 않아야합니다.

편집 :

소수에 어떤 수를 비교하기 전에 3 소수점으로 반올림됩니다

.

+1

정수/long 또는 float/double도 보유하고 있습니까? – BackSlash

+0

예, 가능합니다. String 또는 ArrayList 유형 일 수도 있습니다. 그러나 이러한 경우에는 문자열 대 문자열 비교 또는 ArrayList 대 ArrayList 비교 일뿐입니다. – adbar

+0

해당 정보를 바탕으로 질문이 너무 광범위합니다. 어쩌면 질문을 편집하고 당신이하고 싶은 것을 설명하고 문제를 해결하기 위해 어떤 방법을 고려해 볼 수 있습니까? 당신은 어떤 입력 데이터를 제공하고 그것으로 무엇을해야하는지, 그리고 당신이 어떻게 작업을 수행하려고 하는지를 설명 할 수 있습니다. – BackSlash

답변

1

다음은 편집 된 질문에서 설명한 비교를 정확하게 수행하는 방법입니다.

/** 
* Compare objects for equal value, with some disregard for type. 
* <p> 
* The following types are considered similar, for the purpose of comparing values. The 
* values of the secondary types are converted to the first listed type for value comparison. 
* <ul> 
* <li>{@code long}, {@code int}, {@code short}</li> 
* <li>{@code double} <i>(rounded to 3 decimals before comparing)</i></li> 
* <li>{@code String}, {@code Timestamp}</li> 
* <li>Array <i>(elements are compared using this method, comparison is "deep")</i></li> 
* </ul> 
* Values for all other types are only considered equal if they have the exact same type 
* and {@code equals()} return {@code true}. 
* 
* @param obj1 the first object to be compared. 
* @param obj2 the second object to be compared. 
* @return {@code true} only if the specified objects are equals according to the rules listed above. 
*/ 
public static boolean equalValue(Object obj1, Object obj2) { 
    // Compare null values 
    if (obj1 == null) 
     return (obj2 == null); 
    if (obj2 == null) 
     return false; 

    Class<?> class1 = obj1.getClass(); 
    Class<?> class2 = obj2.getClass(); 

    // Compare double values, rounded to 3 decimal places 
    if (class1 == Double.class && class2 == Double.class) { 
     // Can't use Math.round() because it doesn't do round-half-up, and may overflow long value-range 
     BigDecimal dec1 = BigDecimal.valueOf(((Number)obj1).doubleValue()).setScale(3, RoundingMode.HALF_UP); 
     BigDecimal dec2 = BigDecimal.valueOf(((Number)obj2).doubleValue()).setScale(3, RoundingMode.HALF_UP); 
     return dec1.equals(dec2); // equals() is ok, since we know they have same scale 
    } 

    // Compare arrays 
    if (class1.isArray() && class2.isArray()) { 
     int len = Array.getLength(obj1); 
     if (len != Array.getLength(obj2)) 
      return false; 
     for (int i = 0; i < len; i++) 
      if (! equalValue(Array.get(obj1, i), Array.get(obj2, i))) 
       return false; 
     return true; 
    } 

    // Now that special cases are done, apply simple comparison for values of same type 
    if (class1 == class2) 
     return obj1.equals(obj2); 

    // Compare long/int/short values 
    if ((class1 == Long.class || class1 == Integer.class || class1 == Short.class) && 
     (class2 == Long.class || class2 == Integer.class || class2 == Short.class)) { 
     return ((Number)obj1).longValue() == ((Number)obj2).longValue(); 
    } 

    // Compare String/Timestamp values 
    if ((class1 == String.class || obj1 instanceof Timestamp) && 
     (class2 == String.class || obj2 instanceof Timestamp)) { 
     return obj1.toString().equals(obj2.toString()); 
    } 

    return false; // Incomparable types 
} 
1

toStringtoString()이 동일한 값이지만 다른 객체 유형에 대해 동일한 표현을 반환하는 경우에만 사용할 수 있습니다.

int와 long의 경우 인 경우 int는 할당 할 수있는 범위의 범위 내에 있으면 일 수 있습니다.

것은 두 번이었고,이 때문에 소수점 등 그들이 동일한 개체의 equals()의 구현이 충분해야 입력을하는 경우

에 값의 하위 집합 잘되지 않을 것 int로합니다.

사용 사례에 따라 다른 타임 스탬프와 비교하여 int를 서로 비교하여 발생한 문자열에서 타임 스탬프를 만들 수 있습니다.

bigint를 long으로 나타내야하므로 smallint와 int 값을 long으로 변환하면 equals 메서드에 의존 할 수 있습니다.

+0

@ Orin2005'long '이'int' 범위 밖에 있다면 그것은 같지 않아야합니다. –

+0

Long 값이 int 범위를 벗어나는 경우 Orin2005는 오류없이 정상적으로 작동합니다. 그것은 단지 거짓을 반환합니다. – FredK

1

"다른 유형, 동일한 가치"의 개념은 실제로 무의미합니다. 유형이 표준 변환 (확장, 축소, [un] 복싱, 문자열 ...)에 의해 관련이 없으면 정의에 따라 유형이 비교 될 수 없습니다. 그들은 담론의 영역이 서로 다릅니다. 그것은 Avoirdupois 파운드를 파운드와 비교하는 것과 같습니다. 의미 론적 관계는 없습니다.

비교 가능성에 대한 개념과 일치시키려는 의미 론적 관계를 부과 할 수 있지만,이 경우 "값"을 일반적인 유형으로 표준 방식으로 가져와야합니다. 새로운 BigDecimal (new BigInteger ("1"), 2)는 다른 방법으로 'String'으로 바뀔 수 있습니다. 'toString()'이 대답이라고 생각하면 '1', (int) 1, 그리고 그것은 당신이 원하는 것일 수도 아닐 수도 있습니다.

호환되지 않는 유형을 어떻게 비교하는지는 전적으로 귀하에게 달려 있습니다. 호환되지 않는 경우 규칙을 왜곡하므로 규칙을 왜곡해야합니다.나는 당신이 비교하기를 원하는 도메인을 통해 생각하고, 호환되지 않는 비교를 처리 할 계획이 왜곡되어 있는지 강력하게 제안합니다.

호환되는 비교는 물론 inbuilt 메커니즘을 사용해야합니다.

+0

일치하는 데이터 유형을 갖도록 테이블 전체를 다시 만들면 여전히 첫 번째 옵션입니다. 이 코드를 사용하는 누군가가 일치하는 데이터 유형을 가지고 있지 않을 경우를 대비해 코드에 기능을 추가하려고합니다. 그럴 경우에 대비할 수 있어야합니다. 나는 당신의 요점을 보았다. 그들이 같은 유형이 아니라면, 그들은 동일하지 않습니다. 하지만 어떤 사람들은 타입을 바꾸고 싶을 수도 있습니다 ... – adbar

0

당신이 비교하고있는 모든 객체가 숫자 인 것을 안다면 java.math.BigDecimal 인스턴스로 변환하여 비교할 수 있습니다.

Objects.equals(new BigDecimal(a.toString()), new BigDecimal(b.toString())); 
0

Objects.equals (a, b)는 a와 b가 null이 아닌 경우 내부적으로 a.equals (b)를 호출합니다.
a는 실제로 Long 타입입니다. Obect로 선언해도 상관 없습니다. Long a.equals (b)의 문서에 따르면 b가 long 유형인지 확인합니다. 그것이 거짓으로 돌아간 이유입니다.
USING toString()은 숫자 객체를 비교하는 가장 좋은 방법으로 보이지 않습니다.
기본 유형 비교에 longValue(), intValue() 등의 메소드를 사용하는 것이 좋습니다.

+0

Object 타입의 .int/longValue() 메소드를 호출 할 수 없습니다. 비교하기 전에 어떤 유형 인지도 알 수 없습니다. – adbar

관련 문제