tags:

views:

297

answers:

6
A: 

Have you tried this ?

// Test if both arrays are of the same type
if (array1.class.getComponentType.equals(array2.class.getComponentTYpe)) {
    // Polymorphism FTW !
    return Arrays.equals(array1, array2);
}
Olivier Croisier
Overloaded methods are not runtime polymorphic.
Michael Borgwardt
You have to cast them somehow, since there is no `Arrays.equals(Object, Object)` overload.
Michael Myers
+2  A: 

I'm afraid the only alternative would be to use reflection, which would be nearly as ugly.

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

Not tested, could fail in all kinds of ways, needs lots of exception handling...

Michael Borgwardt
You can't use `obj1.getClass()` directly since non-primitive arrays need to use the `Object[]` overload.
polygenelubricants
Damn! It was such a nice one-liner...
Michael Borgwardt
This one liner (which could be made even nicer with varargs) could still work once arrays are confirmed primitive. The non-primitive case could be handled separately, possibly using `deepEquals` instead.
polygenelubricants
Heh. Nice. +1 for a workable solution, but this goes a little further the OTHER direction than I'd prefer; I try not to golf in code somebody else will have to maintain. :-)
BlairHippo
A: 

Maybe the Strategy Pattern can help it look better :)

al nik
+4  A: 

You can use reflection.

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);
}

Reflection is only used to find the right method at run-time without the eyesore you're looking to avoid; the actual Arrays.equals method should run pretty fast.

Obviously production version needs more robust exception handling. You may also want to use deepEquals(Object[], Object[]) instead of equals(Object[], Object[]) for non-primitive arrays.

polygenelubricants
Exactly what I was looking for. You have my thanks.
BlairHippo
A: 

You can use the getClass() method without isArray(); check out this example:

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));

I admit up front that this is far from a perfect solution. It shortens the potentially huge if-else chain that you had in the original post, but causes errors if the types are not the same. The following similar code wouldn't even compile in 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));

IF you are confident that you won't have type mismatches and your only problem is that you don't want to figure out which type you have, this could work.

Lord Torgamus
As other commenters have noted, there's no such thing as Arrays.equals(Object, Object); I'd need to cast obj1 and obj2 into something when I make the call.
BlairHippo
Do you have an example of a situation in which this would not work? There IS a "equals(Object[] a, Object[] a2)" method, and you're already checking that you have arrays.
Lord Torgamus
My inputs are a pair of Objects. They could be of type Object[], or of type boolean[], or whatever. But because Object[] != Object, I can't just pass them in to Arrays.equals() raw and expect it to handle them; it doesn't have the necessary method. And converting the arrays to Object[] arrays will blow up if I try it on arrays of primitive types.
BlairHippo
Ah, I didn't know you were passing Objects in (may I suggest that you edit your post to reflect that?). In that case, you are of course correct. Sorry I couldn't be more helpful.
Lord Torgamus
No worries, I appreciate the effort. :-)
BlairHippo
A: 

you can use the enum strategy pattern to create a comparator for each type:

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);
   }

}

Error handling omitted, but of course, you want to throw IllegalArgumentException wherever incorrect types are passed around (I prefer to let ClassCastException be JVM generated, and throw IAE in my own code when I detect something wrong).

LES2
Well, it cleans-up the equals() method quite a lot, which is technically what I'm asking for. But it just moves the complexity elsewhere, so I think I'll go with a different solution.
BlairHippo
Agreed. The cleanest solutions so far seem to be the reflection-based. I was just providing a alternative that doesn't use reflection.
LES2