arrays and cloning, where is it described?

  • Thread starter Andreas Leitgeb
  • Start date
M

Mike Schilling

Lew said:
/op. cit./, /supra/.


If we keep repeating the information enough, eventually it will get
through. It certainly is mentioned in enough places in the JLS:


Not very good OO programmers, are they? Every array class has the
same "length" field, so it should be moved up into an abstract
superclass. :)
 
A

Andreas Leitgeb

Lew said:
What clone() does is, strangely, documented in the Javadocs for clone(),
specifically,
....which doesn't mention arrays at all.

For a normal class I can override .clone and provide for deep-copying,
but how could I override an array's clone()?
Which I cannot do with arrays.
The details of what it does to an array are covered in one of the JLS links I
mentioned:
An array thus has the same public fields and methods as the following
class:
...
public T[] clone() {
try {
return (T[])super.clone(); // unchecked warning
} catch (CloneNotSupportedException e) {
throw new InternalError(e.getMessage());
}
...

I saw that, but I found it nowhere near explicitly saying
that this was the actual implementation of an array's clone().
It rather says that if it *were* the implementation then
soem warning would occur.
Taken together, these two sources answer your question.

It gives lots of hints, but nothing explicit.
I'm "quite" sure, that array clones are shallow, but I already
was so at start of this thread. The "quite" is still there.
 
L

Lew

Andreas said:
It gives lots of hints, but nothing explicit.
I'm "quite" sure, that array clones are shallow, but I already
was so at start of this thread. The "quite" is still there.

Good thing you are correct, then.
 
L

Lew

Mike said:
Not very good OO programmers, are they? Every array class has the
same "length" field, so it should be moved up into an abstract
superclass. :)

Actually, it's each array /instance/ that has a 'length'. Such a field is an
instance member, not a class member.

Furthermore, it isn't actually a field. Even were 'length' actually a field,
and there were an actual superclass that defined it, its behavior would be the
same, from the Java language perspective, as observed today.

The implementation of 'length' does provide that abstractness, in that the
implementation is not specific to each array, but general for all arrays.
Conceptually, it's just precisely exactly quite as if indeed there were an
abstract array superclass that defines 'length'. The definition of 'length'
lives in the (imaginary) abstract superclass of array, the instance and
initialization of a 'length' live in each array instance.

So I have to disagree, 'they" are pretty good OO programmers.
 
P

Piotr Kobzda

Andreas said:
The other question was, if there exists some method for deepCopying
an array of Cloneables.

I don't know of any standard method to do that. However, it's not so
hard to roll your own.

Here is one possible approach presented:


import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.IdentityHashMap;
import java.util.Map;


public class ArraysCloning {

public static void main(String[] args) {
String[][] a0 = {{"a"}, {"b", "c"}};
String[][] a1 = a0.clone();
String[][] a2 = Arrays.copyOf(a0, a0.length);
String[][] a3 = deepClone(a0);

a0[1][1] = "c'";

System.out.println("a0=" + Arrays.deepToString(a0));
System.out.println("a1=" + Arrays.deepToString(a1));
System.out.println("a2=" + Arrays.deepToString(a2));
System.out.println("a3=" + Arrays.deepToString(a3));
}

public static <T> T[] deepClone(T[] a) {
return deepClone(a, new IdentityHashMap<Object, Object>());
}

@SuppressWarnings("unchecked")
private static <T> T deepClone(T a, Map<Object, Object> cloned) {
if (a == null) return null; // null clones to null
if (! a.getClass().isArray()) return a; // non-array clones to self
T c = (T) cloned.get(a);
if (c != null) return c; // already cloned clones to clone
// clone...
try {
c = (T) cloneMethod.invoke(a, (Object[])null);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getCause());
}
// remember clone
cloned.put(a, c);
// clone non-primitive array elements...
if (! c.getClass().getComponentType().isPrimitive()) {
Object[] ca = (Object[]) c;
for(int i = 0, len = ca.length; i < len; ++i) {
ca = deepClone(ca, cloned);
}
}
return c;
}

private static final Method cloneMethod;
static {
try {
cloneMethod = Object.class
.getDeclaredMethod("clone", (Class<?>[])null);
cloneMethod.setAccessible(true);
} catch (Exception e) {
throw new Error(e);
}
}
}


Which prints out the following:
a0=[[a], [b, c']]
a1=[[a], [b, c']]
a2=[[a], [b, c']]
a3=[[a], [b, c]]


(To make an example shorter it utilizes reflective clone() invocation
for each array type -- primitive and reference arrays. When maximum
speed (and safety) is needed it may be reimplemented to directly call
clone() depending on a component type of array being cloned -- just a
bit more of "ugly coding" needed...)


piotr
 
M

Mike Schilling

Lew said:
Actually, it's each array /instance/ that has a 'length'. Such a
field is an instance member, not a class member.

OK, say "defines" instead of "has", if you want to be a stickler.
 
A

Andreas Leitgeb

Piotr Kobzda said:
I don't know of any standard method to do that. However, it's not so
hard to roll your own.

Thanks for your code sample.
I didn't yet think of the case where several array-elements might
refer to the same Object. While it won't happen in my case, it is
now clear to me that a general solution is more than just a loop
cloning each Element to the new array. Now, I'm somewhat less
surprised by the lack of such a method in "Arrays".

Meanwhile in my case I noticed that I don't really need to clone
the whole array, but only generate a "digest" from it, but now
having a deepCopy-implementation findable in google is still a
good thing :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top