-1

I found a useful method here
but it fails to work with classes with array members e.g.

public class Test {
    int [] arr = new int[2];
}

Full code from the answer mentioned above
with my failing attempts to instantiate new array:

public static Object cloneObject(Object _obj) {
    try {
        // begin my changes
        Object copy = null;
        if (!_obj.getClass().isArray())
            copy = _obj.getClass().newInstance();
        else {
            int len = Array.getLength(_obj);
            Class type = _obj.getClass().getComponentType();
            // Next line fails with: Compiler(syntax) error
            // copy = (type.getClass()[])Array.newInstance(_obj.getClass(), len);
            // Next line fails with: "InstantiationException: int cannot be instantiated"
            // copy = _obj.getClass().getComponentType().newInstance();
            // how then?
        }
        // end my changes
        for (Field field : _obj.getClass().getDeclaredFields()) {
            field.setAccessible(true);
            if (field.get(_obj) == null || Modifier.isFinal(field.getModifiers()))
                continue;
            if (field.getType().isPrimitive() ||
                field.getType().equals(String.class) ||
                field.getType().getSuperclass().equals(Number.class) ||
                field.getType().equals(Boolean.class)
            )
                field.set(copy, field.get(_obj));
            else {
                Object child = field.get(_obj);
                if (child == _obj)
                    field.set(copy, copy);
                else
                    field.set(copy, cloneObject(field.get(_obj)));
            }
        }
        return copy;
    } catch (Exception _e){
        return null;
    }
}

Is it even possible to achieve?

Community
  • 1
  • 1
Alexey Andronov
  • 582
  • 6
  • 28

2 Answers2

1

Note that every array type has a clone method which you can use like

int[] array={ 1, 2, 3 }, copy=array.clone();

Unfortunately, this method is not reported by Reflection, so in order to invoke it reflectively, you have to lookup Object.clone() and, since this base class’ method is declared protected, make it accessible via setAccessible(true) despite the fact that the array’s overriding method is public.

Further, this creates only a shallow copy, so in case of object arrays or multiple dimensions, you have to repeat this step recursively. But since all multi-dimensional arrays are also a subtype of Object[], they can be handled uniformly:

if(_obj.getClass().isArray()) {
    Method cloneMethod = Object.class.getDeclaredMethod("clone");
    cloneMethod.setAccessible(true);
    copy=cloneMethod.invoke(_obj);
    if(copy instanceof Object[]) {
        Object[] array=(Object[])copy;
        for (int ix = 0; ix < array.length; ix++)
            array[ix]=cloneObject(array[ix]);
    }
    return copy;
}
Holger
  • 285,553
  • 42
  • 434
  • 765
0

You don't need to cast the array that is returned by the Array.newInstance method as you are assigning it to a variable of type Object (which will accept any object, and arrays are also objects)

Just do:

copy = Array.newInstance(type, len);
Erwin Bolwidt
  • 30,799
  • 15
  • 56
  • 79
  • now it fails on line `field.set(copy, cloneObject(field.get(_obj)));` with `IllegalArgumentException: "field Test.arr has type int[], got int[][]"` – Alexey Andronov Jul 12 '16 at 10:33
  • @AlexeyAndronov You asked about your changes and I answered your question. It looks like you say that part works now, so I guess it's the correct answer. If you have a new question, please ask it as a separate question. – Erwin Bolwidt Jul 12 '16 at 14:58
  • 1
    @Alexey Andronov: you have to use `type` just like in this answer rather than `_obj.getClass()`, as `Array.newInstance` expects the component type. But note that this only creates a new array of the same type, not a copy. – Holger Jul 13 '16 at 13:41