【问题标题】:Java Array ComparisonJava 数组比较
【发布时间】:2010-03-22 15:59:45
【问题描述】:

在 Java 中工作,假设我有两个对象,感谢obj.getClass().isArray(),我知道它们都是数组。让我们进一步说,我想将这两个数组相互比较——可能使用Arrays.equals。有没有一种优雅的方法可以做到这一点,而无需求助于一个详尽的 if/else 树来确定需要使用哪种风格的 Arrays.equals?我正在寻找比这更不碍眼的东西:


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

【问题讨论】:

    标签: java arrays


    【解决方案1】:

    你可以使用反射。

    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 方法应该运行得非常快。

    显然生产版本需要更强大的异常处理。对于非原始数组,您可能还想使用 deepEquals(Object[], Object[]) 而不是 equals(Object[], Object[])

    【讨论】:

      【解决方案2】:

      恐怕唯一的选择是使用反射,这几乎是丑陋的。

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

      未经测试,可能以各种方式失败,需要大量异常处理...

      【讨论】:

      • 你不能直接使用obj1.getClass(),因为非原始数组需要使用Object[]重载。
      • 一旦数组被确认为原语,这一衬里(可以使用可变参数做得更好)仍然可以工作。非原始情况可以单独处理,可能使用deepEquals
      • 嘿。好的。 +1 是一个可行的解决方案,但这比我更喜欢的 OTHER 方向更进一步;我尽量不使用其他人必须维护的代码。 :-)
      【解决方案3】:

      也许Strategy Pattern 可以帮助它看起来更好:)

      【讨论】:

        【解决方案4】:

        您可以在没有isArray() 的情况下使用getClass() 方法;看看这个例子:

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

        如果您确信自己不会出现类型不匹配,并且您唯一的问题是您不想弄清楚 您拥有哪种类型,那么这可能会奏效。

        【讨论】:

        • 正如其他评论者所指出的,没有 Arrays.equals(Object, Object); 这样的东西。拨打电话时,我需要将 obj1 和 obj2 转换为某些东西。
        • 你有一个例子说明这不起作用吗?有一个“equals(Object[] a, Object[] a2)”方法,你已经在检查你是否有数组。
        • 我的输入是一对对象。它们可以是 Object[] 类型,或 boolean[] 类型,或其他类型。但是因为 Object[] != Object,我不能只将它们传递给 Arrays.equals() raw 并期望它处理它们;它没有必要的方法。如果我在原始类型的数组上尝试,将数组转换为 Object[] 数组将会爆炸。
        • 啊,我不知道您正在传递对象(我可以建议您编辑您的帖子以反映这一点吗?)。在那种情况下,你当然是正确的。抱歉,我不能提供更多帮助。
        • 别担心,我很感激你的努力。 :-)
        【解决方案5】:

        您可以使用枚举策略模式为每种类型创建一个比较器:

        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(我更喜欢让 ClassCastException 由 JVM 生成,并在我检测到错误时在我自己的代码中抛出 IAE)。

        【讨论】:

        • 嗯,它清理了 equals() 方法很多,这在技术上是我所要求的。但这只是将复杂性转移到其他地方,所以我想我会采用不同的解决方案。
        • 同意。到目前为止,最干净的解决方案似乎是基于反射的。我只是提供了一个不使用反射的替代方案。
        【解决方案6】:

        你试过了吗?

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

        【讨论】:

        • 重载的方法不是运行时多态的。
        • 你必须以某种方式投射它们,因为没有Arrays.equals(Object, Object) 重载。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-18
        • 1970-01-01
        • 2016-08-26
        相关资源
        最近更新 更多