2010-03-22 5 views
9

Java 내에서 작업 할 때, obj.getClass().isArray() 덕분에 두 개의 객체가 있다고 가정 해 봅시다. 더 나아가이 두 배열을 서로 비교하기를 원합니다. 아마도 Arrays.equals을 사용하면됩니다. Arrays.equals의 맛을 알아내는 데 필요한 완전한 철저한 if/else 트리를 사용하지 않고이 작업을 수행하는 우아한 방법이 있습니까? 나는 이보다 더 눈에 띄지 않는 것을 찾고 있습니다.Java 배열 비교


     if (obj1 instanceof byte[] && obj2 instanceof byte[]) { 
     return Arrays.equals((byte[])obj1, (byte[])obj2); 
     } 
     else if (obj1 instanceof boolean[] && obj2 instanceof boolean[]) { 
     ... 

답변

8

당신은 반사를 사용할 수 있습니다 :) 더 잘 도울 수 ... 예외 처리를 많이 필요, 방법의 모든 종류에 실패 할 수 있습니다.

public static boolean arrayEquals(Object arr1, Object arr2) throws Exception { 
    Class<?> c = arr1.getClass(); 
    if (!c.getComponentType().isPrimitive()) { 
     c = Object[].class; 
    } 
    Method m = Arrays.class.getMethod("equals", c, c); 
    return (Boolean) m.invoke(null, arr1, arr2); 
} 

반사는 실행시에 눈에 띄지 않는 피해를 피하기 위해 사용됩니다. 실제 Arrays.equals 메서드는 매우 빠르게 실행되어야합니다.

분명히 프로덕션 버전에는보다 강력한 예외 처리가 필요합니다. 비 프리미티브 배열의 경우 equals(Object[], Object[]) 대신 deepEquals(Object[], Object[])을 사용할 수도 있습니다.

+0

정확히 내가 무엇을 찾고 있었습니까. 너는 고맙다. – BlairHippo

-1

시도해 보셨습니까?

// Test if both arrays are of the same type 
if (array1.class.getComponentType.equals(array2.class.getComponentTYpe)) { 
    // Polymorphism FTW ! 
    return Arrays.equals(array1, array2); 
} 
+1

오버로드 된 메서드는 런타임 다형성이 아닙니다. –

+0

'Arrays.equals (Object, Object)'오버로드가 없으므로 어떻게 든 캐스트해야합니다. –

2

유일한 대안은 반사를 사용하는 것입니다. 이는 거의 추악 할 것입니다. 테스트하지

Arrays.getClass() 
     .getMethod("equals", new Class[]{obj1.getClass(), obj2.getClass()}) 
     .invoke(null, new object[]{obj1, obj2}); 

+0

비 기본 배열은'Object []'과부하를 사용해야하기 때문에'obj1.getClass()'를 직접 사용할 수 없습니다. – polygenelubricants

+0

젠장! 정말 멋진 한 줄 이었어. –

+0

이 한 라이너 (varargs로 더 멋지게 만들 수 있음)는 배열이 프리미티브로 확인되면 여전히 작동 할 수 있습니다. non-primitive의 경우는'deepEquals'를 대신 사용하여, 개별적으로 처리 할 수 ​​있습니다. – polygenelubricants

0

getClass() 메서드는 isArray()없이 사용할 수 있습니다. 이 예제를 체크 아웃 :

byte[] foo = { 1, 2 }; 
byte[] bar = { 1, 2 }; 

System.out.println(foo.getClass()); 
System.out.println(bar.getClass()); 

if(foo.getClass() == bar.getClass()) 
    System.out.println(Arrays.equals(foo, bar)); 

나는 이것이 완벽한 해결책에서 멀리이다 앞을 인정한다. 원래 게시물에서 가지고 있던 잠재적 인 거대한 if-else 체인을 줄이지 만 유형이 동일하지 않으면 오류가 발생합니다. 다음과 같은 코드도은 MyEclipse 8.0에서 컴파일되지 것입니다 :

당신이 타입 불일치와 유일한 문제가되지 않습니다 확신 경우
byte[] obj1 = { 1, 2 }; 
String[] obj2 = { "1", "2" }; 

System.out.println(obj1.getClass()); 
System.out.println(obj2.getClass()); 

if(obj1.getClass().toString().equals(obj2.getClass().toString())) 
    System.out.println(Arrays.equals(obj1, obj2)); 

당신이 유형을 파악하지 않는다는 것입니다 너는 가지고있다, 이것은 일할 수 있었다.

+0

다른 주석가들이 지적했듯이, Arrays.equals (Object, Object); 제가 전화를 걸 때 obj1과 obj2를 무언가에 던져 넣어야합니다. – BlairHippo

+0

이것이 작동하지 않는 상황의 예가 있습니까? "equals (Object [] a, Object [] a2)"메서드가 있으며 이미 배열이 있는지 확인하고 있습니다. – Pops

+0

내 입력은 한 쌍의 객체입니다. 그것들은 Object [] 타입이거나, boolean [] 타입이거나, 뭐든 상관 없다. 그러나 Object []! = Object이기 때문에 Arrays.equals()를 전달하지 않고 처리 할 수는 없습니다. 필요한 방법이 없습니다. 그리고 배열을 Object [] 배열로 변환하면 원시 형 배열로 배열을 시도해 볼 수 있습니다. – BlairHippo

0

각 유형에 대한 비교를 만들 열거 전략 패턴을 사용할 수 있습니다

public enum ArrayEq { 
    BYTE_PRIMITIVE(Byte.TYPE) { 
     protected boolean doEquals(Object array1, Object array2) { 
      return Arrays.equals((byte[]) array1, (byte[]) array2); 
     } 
    }, 
    ... enum element for each component type 

    private final Class<?> type; 

    private ArrayEq(final Class<?> type) { this.type = type; } 
    public Class<?> getComponentType() { return type; } 

    // force all enums to implement this method 
    protected abstract boolean doEquals(Object array1, Object array2); 

    public static boolean equals(Object array1, Object array2) { 
     if(array1 == null) return array2 == null; 

     // you need to populate this map in a static initializer of the enum 
     // a simple linear search would work too since the number of elements is small 
     typeToElementMap.get(array1.getComponentType()) 
      .doEquals(array1, array2); 
    } 

}

오류가 생략 처리,하지만 잘못된 유형의 주위에 전달되는 곳 물론, 당신은, IllegalArgumentException를 throw 할 (나는 ClassCastException을 JVM이 생성되도록하고, 잘못된 것을 발견했을 때 IAE를 내 코드에 던지기를 선호한다.)

+0

글쎄, 그것은 equals() 메소드를 꽤 많이 정리합니다. 이것은 기술적으로 내가 요구하는 것입니다. 하지만 복잡성이 다른 곳으로 옮겨지기 때문에 다른 해결책을 찾아 볼 것입니다. – BlairHippo

+0

동의. 지금까지 가장 깨끗한 솔루션은 반사 기반 인 것처럼 보입니다. 나는 반사를 사용하지 않는 대안을 제공하고 있었다. – les2