如何将java Object强制转换为自己的getComponentType?

时间:2017-08-16 14:02:01

标签: java arrays casting

我有一个包含私人对象列表的类。

private List<Object> mylist;

此外,我的课程包含两种方法:

(1) addObject

public void addObject(Object obj)
{
    this.mylist.add(obj);
}

(2) dropObject

dropObject有点棘手。我想将mylist中与信号obj相等(但不相同)的第一个元素删除。因此,我将参数obj的类与mylist中的每个元素的类进行比较。如果当前元素的类匹配,我想比较两个元素是否相等(但不相同)。

这里我有一些比较数组的问题。我想使用Array.deepEquals(),这需要对objcurr_obj进行类型转换。

所以这是我的代码:

public void dropArgument(Object obj) {

    if (obj == null) {
        return;
    }

    Object objRemove = null;

    for (Object curr_obj : this.mylist) {

        if (curr_obj.getClass() != obj.getClass()) {
            continue;
        }

        // primitive data type comparison
        if (obj.getClass().isPrimitive() && curr_obj == obj) {
            objRemove = curr_obj;
        } 
        // array comparison
        else if ((obj.getClass().isArray())
                /* the following line gives me headache */
                && (Arrays.deepEquals((Object[]) curr_obj, (Object[]) obj))) {
            objRemove = curr_obj;
        }
        // wrapper / collection comparison
        else if (curr_obj.equals(obj)) {
            objRemove = curr_obj;
        }
        // comparison of any other classes which are assumed not to have an 'equals' method.
        else {
            Field[] fInputFields = obj.getClass().getDeclaredFields();
            Field[] fFields = curr_obj.getClass().getDeclaredFields();
            if (Arrays.deepEquals(fInputFields, fFields)) {
                objRemove = curr_obj;
            }
        }
    }

    // delete obj match if found
    if (objRemove != null) {
        this.mylist.remove(objRemove);
    }
}

我为这个方法编写了测试,并且每种类型的数组得到以下内容(int []数组的stackstrace):

error:
java.lang.ClassCastException: [I cannot be cast to [Ljava.lang.Object;
    at javafxTablePane.FieldMethodData.dropArgument(FieldMethodData.java:119)
    at tests.DropArgumentsTests.test_dropMultiArrayInteger(DropArgumentsTests.java:345)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

错误很明显:int[]不能被Object[]类型化。所以我的问题是,由于Array.deepEquals()需要类型转换,我如何将对象重新转换为它们自己的类/数据类型作为数组?

我搜索了这个,发现getClass().getComponentType()方法提供了我的对象的数组类型。但我不知道(如果可能的话)如何使用它来将obj强制转换为自己的数组类型。

其他一些信息:

  1. 我想使用Object obj作为我的方法的参数,以便能够获得独立于类或数据类型的任何对象。
  2. 我知道,我可以简单地重载我的方法来处理每种数据类型本身。但我试着解决这个问题。
  3. 更新

    我遵循了Darshan Mehta的建议并实现了一个简单的方法,将1维数组从原始类转换为包装类。我可以继续开发更通用的代码(例如,任何维度的数组),因此这个解决方案适合我的问题。我把我的代码放在这里给那些感兴趣的人。

    /**
     * <b>ArrayEquals</b>
     * <p>
     * Compares two arrays of any same class and delivers their equality as boolean.
     * </p>
     * 
     * @param obj1
     *            [Object] : any object of any class as Object
     * @param obj2
     *            [Object] : any object of the same class as obj1 as Object
     * @return [boolean] : Equality of obj1 and obj2
     */
    private boolean ArrayEquals(Object obj1, Object obj2) {
    
        Class<?> cObj1 = obj1.getClass().getComponentType();
    
        // convert byte[] to Byte[]
        if (cObj1.equals(byte.class)) {
    
            byte[] tmpObj1 = (byte[]) obj1;
            byte[] tmpObj2 = (byte[]) obj2;
            if (tmpObj1.length != tmpObj2.length) {
                return false;
            }
            Byte[] newObj1 = new Byte[tmpObj1.length];
            Byte[] newObj2 = new Byte[tmpObj2.length];
    
            for (int i = 0; i < tmpObj1.length; i++) {
                newObj1[i] = tmpObj1[i]; // Autoboxing
                newObj2[i] = tmpObj2[i]; // Autoboxing
            }
            return Arrays.deepEquals(newObj1, newObj2);
        }
        // convert short[] to Short[]
        else if (cObj1.equals(short.class)) {
            short[] tmpObj1 = (short[]) obj1;
            short[] tmpObj2 = (short[]) obj2;
            if (tmpObj1.length != tmpObj2.length) {
                return false;
            }
            Short[] newObj1 = new Short[tmpObj1.length];
            Short[] newObj2 = new Short[tmpObj2.length];
    
            for (int i = 0; i < tmpObj1.length; i++) {
                newObj1[i] = tmpObj1[i]; // Autoboxing
                newObj2[i] = tmpObj2[i]; // Autoboxing
            }
    
            return Arrays.deepEquals(newObj1, newObj2);
        }
        // convert int[] to Integer[]
        else if (cObj1.equals(int.class)) {
            Integer[] newObj1 = Arrays.stream((int[]) obj1).boxed().toArray(Integer[]::new);
            Integer[] newObj2 = Arrays.stream((int[]) obj2).boxed().toArray(Integer[]::new);
            return Arrays.deepEquals(newObj1, newObj2);
        }
        // convert long[] to Long[]
        else if (cObj1.equals(long.class)) {
            Long[] newObj1 = Arrays.stream((long[]) obj1).boxed().toArray(Long[]::new);
            Long[] newObj2 = Arrays.stream((long[]) obj2).boxed().toArray(Long[]::new);
            return Arrays.deepEquals(newObj1, newObj2);
        }
        // convert float[] to Float[]
        else if (cObj1.equals(float.class)) {
            float[] tmpObj1 = (float[]) obj1;
            float[] tmpObj2 = (float[]) obj2;
            if (tmpObj1.length != tmpObj2.length) {
                return false;
            }
            Float[] newObj1 = new Float[tmpObj1.length];
            Float[] newObj2 = new Float[tmpObj2.length];
    
            for (int i = 0; i < tmpObj1.length; i++) {
                newObj1[i] = tmpObj1[i]; // Autoboxing
                newObj2[i] = tmpObj2[i]; // Autoboxing
            }
    
            return Arrays.deepEquals(newObj1, newObj2);
        }
        // convert double[] to Double[]
        else if (cObj1.equals(double.class)) {
            double[] tmpObj1 = (double[]) obj1;
            double[] tmpObj2 = (double[]) obj2;
            if (tmpObj1.length != tmpObj2.length) {
                return false;
            }
            Double[] newObj1 = new Double[tmpObj1.length];
            Double[] newObj2 = new Double[tmpObj2.length];
    
            for (int i = 0; i < tmpObj1.length; i++) {
                newObj1[i] = tmpObj1[i]; // Autoboxing
                newObj2[i] = tmpObj2[i]; // Autoboxing
            }
    
            return Arrays.deepEquals(newObj1, newObj2);
        }
        // convert boolean[] to Boolean[]
        else if (cObj1.equals(boolean.class)) {
            boolean[] tmpObj1 = (boolean[]) obj1;
            boolean[] tmpObj2 = (boolean[]) obj2;
            if (tmpObj1.length != tmpObj2.length) {
                return false;
            }
            Boolean[] newObj1 = new Boolean[tmpObj1.length];
            Boolean[] newObj2 = new Boolean[tmpObj2.length];
    
            for (int i = 0; i < tmpObj1.length; i++) {
                newObj1[i] = tmpObj1[i]; // Autoboxing
                newObj2[i] = tmpObj2[i]; // Autoboxing
            }
    
            return Arrays.deepEquals(newObj1, newObj2);
        }
        // convert char[] to Character[]
        else if (cObj1.equals(char.class)) {
            char[] tmpObj1 = (char[]) obj1;
            char[] tmpObj2 = (char[]) obj2;
            if (tmpObj1.length != tmpObj2.length) {
                return false;
            }
            Character[] newObj1 = new Character[tmpObj1.length];
            Character[] newObj2 = new Character[tmpObj2.length];
    
            for (int i = 0; i < tmpObj1.length; i++) {
                newObj1[i] = tmpObj1[i]; // Autoboxing
                newObj2[i] = tmpObj2[i]; // Autoboxing
            }
            return Arrays.deepEquals(newObj1, newObj2);
        }
        // is no primitive
        else {
            return Arrays.deepEquals((Object[]) obj1, (Object[]) obj2);
        }
    }
    

1 个答案:

答案 0 :(得分:3)

在比较两个对象时,您应该执行以下操作:

  • 将比较逻辑抽取为新方法(例如private boolean equals(Object o1, Object o2),并使用dropObject方法调用)。
  • 对于Array类型,使用array.getClass().getComponentType()方法调用获取组件类型,并尝试将其强制转换为适当的数组。将int数组转换为Object数组将抛出ClassCastException。有关强制转换和数组类型的更多说明,请参阅this SO答案。
  • 如果组件类型是数组,则实现逻辑以迭代所有元素,并为每个元素调用equals方法。
相关问题