Java Forum / General / March 2008
arrays and cloning, where is it described?
Andreas Leitgeb - 05 Mar 2008 11:58 GMT It seems to be quite a basic thing, but I found myself unsure about how it works, and where it is described. (I didn't find it in JLS nor in the description of Cloneable or Object.clone() in the javadoc)
According to JLS, arrays are Serializable and Cloneable, and for multidimensional arrays, the JLS says: " A clone of a multidimensional array is shallow, " which is to say that it creates only a single " new array. Subarrays are shared.. I'm not sure if this should be understood to imply shallowness also in my case. Why would it have to explicitly mention multidimensional arrays otherwise?
If I want to deep-copy an array of some Cloneable class, what would be the best way to do it?
I'd be glad about answers, but even more I'd be glad about pointers to any of sun's java-documents (jls, api), where this behaviour or some "deepCopy" method for arrays of cloneable types is directly described.
Is array's clone/copy altogether the wrong way, and do I need to create a new array and fill it with clones of each element, myself?
PS: In my task at hand I do not need to worry about compiletime/runtime-type: they're the same.
Sanny - 05 Mar 2008 12:35 GMT > According to JLS, arrays are Serializable and Cloneable, > and for multidimensional arrays, the JLS says: [quoted text clipped - 4 lines] > shallowness also in my case. Why would it have to > explicitly mention multidimensional arrays otherwise? I tried to copy Single dimensional Array and it works correctly. For multidimensional Array it do not copy all elements as you think.
int[] array1 = new int[100]; int[] source = new int[100];
array1=source.clone() Works correctly.
int[][] array1 = new int[100][100]; int[][] source = new int[100][100];
array1=source.clone() Does not Copy all elements correctly.
Bye Sanny
Looking for Experts: http://www.GetClub.com/Experts.php
Patricia Shanahan - 05 Mar 2008 14:45 GMT > It seems to be quite a basic thing, but I found myself > unsure about how it works, and where it is described. [quoted text clipped - 24 lines] > PS: In my task at hand I do not need to worry about > compiletime/runtime-type: they're the same. The key to understanding this is to accept that Java does not really have multidimensional arrays. It does have arrays whose elements are of another array type, and sometimes pretends they are multidimensional arrays, but not to the extent of making one work consistently as though it were a single array with multiple dimensions.
Thus "new int[3][4]" is a three element array. Each element is a reference to a four element array of int.
Cloning it creates a new three element array. Element n of the new array refers to the same int[4] as element n of the original.
Patricia
Andreas Leitgeb - 05 Mar 2008 17:38 GMT >> According to JLS, arrays are Serializable and Cloneable, >> and for multidimensional arrays, the JLS says: [quoted text clipped - 7 lines] > The key to understanding this is to accept that Java does not really > have multidimensional arrays.... Sorry for obviously being higly misunderstandable.
My problem isn't about arrays of primitive types. Not even really "multidimensional" ones.
The docu says: (in other words) if you clone an "array of array-types" (which are, btw., also Cloneable) then the referenced arrays are *not* cloned. So far so good.
While it almost seems like implied, it doesn't say: if you clone an array of *any Object-type*, (which would effectively include array-types) then only the references, not the objects are cloned.
Why does it say so specifically about arrays of arrays, but not about arrays of *any* objects?
Is it, because people might otherwise think that "arrays of arrays" would be more likely to be deep- cloned than arrays of other objects?
Patricia Shanahan - 05 Mar 2008 17:43 GMT ...
> Why does it say so specifically about arrays of > arrays, but not about arrays of *any* objects? > > Is it, because people might otherwise think that > "arrays of arrays" would be more likely to be deep- > cloned than arrays of other objects? I suspect so. Java pretends just enough multidimensional array support to be confusing.
Patricia
Daniel Pitts - 06 Mar 2008 05:35 GMT > .... >> Why does it say so specifically about arrays of [quoted text clipped - 8 lines] > > Patricia I think it also makes a mention because array references are special. Even though they can be assigned to an Object reference, they aren't really an object. The JLS has to be specific about anything that might be ambiguous otherwise.
 Signature Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
Mike Schilling - 06 Mar 2008 07:21 GMT >> .... >>> Why does it say so specifically about arrays of [quoted text clipped - 13 lines] > really an object. The JLS has to be specific about anything that > might be ambiguous otherwise. In what ways are arrays not objects?
Andreas Leitgeb - 06 Mar 2008 07:34 GMT >>>> Why does it say so specifically about arrays of >>>> arrays, but not about arrays of *any* objects? [quoted text clipped - 8 lines] >> really an object. The JLS has to be specific about anything that >> might be ambiguous otherwise. But then it is still unspecific about cloning arrays of Objects. ...or I've just still failed to find that mentioned.
> In what ways are arrays not objects? Don't know, if that's what Daniel meant, but arrays are not accessed through get-/putfield (except for length) or invoke... opcodes, but through <x>aload/<x>astore opcodes for <x> any of [abcdfils].
The JLS has some strange wording, such as "can be assigned to variables of types Object, Cloneable, Serializable", instead of saying that an array *was* all these.
Lew - 06 Mar 2008 08:16 GMT > The JLS has some strange wording, such as "can be assigned to > variables of types Object, Cloneable, Serializable", instead > of saying that an array *was* all these. Actually, the JLS does say that an array is all these, in ss. 4.10.3 <http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.10.3> and in 10.7 <http://java.sun.com/docs/books/jls/third_edition/html/arrays.html#10.7>
> Every array implements the interfaces Cloneable and java.io.Serializable. and 10.8
> The direct superclass of an array type is Object. > Every array type implements the interfaces Cloneable and java.io.Serializable. The combination of Cloneable and Serializable is somewhat rare outside arrays, because Cloneable is rare. The combination is implemented by various java.util classes: ArrayList, Calendar, Date, HashMap, HashSet.
Also in java.sql: Date, Time, Timestamp, by dint of subclassing java.util.Date.
There are a number of additional references in the JLS to the relationship between Cloneable & Serializable and arrays such as ss. 5.1.6 (Narrowing Reference Conversion), 5.5 (Casting Conversion), 10 (Arrays), and 5.2 (Assignment Conversion), from whence your paraphrase seems to come.
<http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.2>
> An array can be assigned only to a variable of a compatible array type, > or to a variable of type Object, Cloneable or java.io.Serializable. That quote makes sense there because it has to do with assignment conversion.
It is also clearly not instead of saying that an array is "all these" but in addition to several such mentions.
 Signature Lew
Andreas Leitgeb - 06 Mar 2008 18:15 GMT >> The JLS has some strange wording, such as "can be assigned to >> variables of types Object, Cloneable, Serializable", instead >> of saying that an array *was* all these. > There are a number of additional references in the JLS to the relationship > between Cloneable & Serializable and arrays ... I skimmed over all of these, but still missed any mention of what clone really does for an array of Objects (or Cloneables, if it made a difference)
It only says, what it does for an array of arrays, but, as has been pointed out in this thread, arrays are not normal Objects ... for some definition of "being" :-)
The other question was, if there exists some method for deepCopying an array of Cloneables.
Lew - 07 Mar 2008 01:03 GMT >>> The JLS has some strange wording, such as "can be assigned to >>> variables of types Object, Cloneable, Serializable", instead [quoted text clipped - 5 lines] > clone really does for an array of Objects (or Cloneables, if it > made a difference) The references were only by way of showing that the JLS does say "that an array *was* all these", not that it explains what clone() does.
What clone() does is, strangely, documented in the Javadocs for clone(), specifically,
> To achieve this independence, it may be necessary to modify one or more fields > of the object returned by super.clone before returning it. > Typically, this means copying any mutable objects that comprise the internal > "deep structure" of the object being cloned and replacing the references to > these objects with references to the copies. The details of what it does to an array are covered in one of the JLS links I mentioned: <http://java.sun.com/docs/books/jls/third_edition/html/arrays.html#10.7>
> public T[] clone() { > try { > return (T[])super.clone(); // unchecked warning > } catch (CloneNotSupportedException e) { > throw new InternalError(e.getMessage()); > } Taken together, these two sources answer your question.
 Signature Lew
Andreas Leitgeb - 07 Mar 2008 10:14 GMT > 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()?
>> To achieve this independence, it may be necessary to modify one or more fields >> of the object returned by super.clone before returning it. 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: [quoted text clipped - 9 lines] >> } >> ... 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.
Lew - 07 Mar 2008 12:30 GMT > 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.
 Signature Lew
Piotr Kobzda - 07 Mar 2008 15:37 GMT > 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[i] = deepClone(ca[i], 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
Andreas Leitgeb - 11 Mar 2008 08:46 GMT >> 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. 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 :-)
Daniel Pitts - 06 Mar 2008 15:19 GMT >>>>> Why does it say so specifically about arrays of >>>>> arrays, but not about arrays of *any* objects? [quoted text clipped - 18 lines] > opcodes, but through <x>aload/<x>astore opcodes for <x> any > of [abcdfils]. Actually, "length", is not a field on an array "object". To access the length of an array, you use a specific opcode. <http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2.doc.html>
> arraylength > Description > > The arrayref must be of type reference and must refer to an array. It is popped from the operand stack. The length of the array it references is determined. That length is pushed onto the operand stack as an int.
> The JLS has some strange wording, such as "can be assigned to > variables of types Object, Cloneable, Serializable", instead > of saying that an array *was* all these. That strange wording is *because* an array is not actually an Object. Programmers are "tricked" into thinking it is, because it can be assigned to an Object/Cloneable/Serializable reference.
 Signature Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
Andreas Leitgeb - 06 Mar 2008 18:29 GMT >> Don't know, if that's what Daniel meant, but arrays are not >> accessed through get-/putfield (except for length) ... > Actually, "length", is not a field on an array "object". To access the > length of an array, you use a specific opcode. ><http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2.doc.html> Sorry, my fault. Thanks for correcting!
//TODO: insert excuse for not checking back *before* posting. ;-)
Patricia Shanahan - 06 Mar 2008 16:20 GMT ...
>> In what ways are arrays not objects? > > Don't know, if that's what Daniel meant, but arrays are not > accessed through get-/putfield (except for length) or invoke... > opcodes, but through <x>aload/<x>astore opcodes for <x> any > of [abcdfils]. That is an implementation detail in compilers that target bytecode, not a Java language feature.
Patricia
Mike Schilling - 06 Mar 2008 18:11 GMT > ... >>> In what ways are arrays not objects? [quoted text clipped - 6 lines] > That is an implementation detail in compilers that target bytecode, not > a Java language feature. What Patricia said.
All of the array types (i.e. array of X) are subclasses [1] of Object; to me, that says that arrays are objects.
1. Descendents, anyway. Do we know for a fact that their immediate superclass is Object?
Daniel Pitts - 06 Mar 2008 18:24 GMT Mike Schilling wrote:
>> ... >>>> In what ways are arrays not objects? [quoted text clipped - 12 lines] > 1. Descendents, anyway. Do we know for a fact that their immediate > superclass is Object? public class Foo { public static void main(String[] args) { System.out.println("Class: " + args.getClass()); System.out.println("Super: " + args.getClass().getSuperclass()); final List<? extends Class<?>> interfaces = Arrays.asList(args.getClass().getInterfaces()); System.out.println("Interfaces: " + interfaces); final List<Field> fields = Arrays.asList(args.getClass().getFields()); System.out.println("Fields:" + fields); final List<Field> declaredFields = Arrays.asList(args.getClass().getDeclaredFields()); System.out.println("Declared Fields:" + declaredFields);
} }
Class: class [Ljava.lang.String; Super: class java.lang.Object Interfaces: [interface java.lang.Cloneable, interface java.io.Serializable] Fields:[] Declared Fields:[]
 Signature Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
Mike Schilling - 06 Mar 2008 19:54 GMT > Mike Schilling wrote: >>> ... [quoted text clipped - 36 lines] > Fields:[] > Declared Fields:[] Yes, I know that the superclass is Object *now*, but I don't know whether this is guaranteed.
Patricia Shanahan - 06 Mar 2008 20:12 GMT Mike Schilling wrote: ...
> Yes, I know that the superclass is Object *now*, but I don't know whether > this is guaranteed. http://java.sun.com/docs/books/jls/third_edition/html/arrays.html#10.8
"The direct superclass of an array type is Object."
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getSuperclass()
"If this object represents an array class then the Class object representing the Object class is returned."
Patricia
Lew - 07 Mar 2008 01:08 GMT > Mike Schilling wrote: > .... >> Yes, I know that the superclass is Object *now*, but I don't know >> whether this is guaranteed. > > http://java.sun.com/docs/books/jls/third_edition/html/arrays.html#10.8 /op. cit./, /supra/.
> "The direct superclass of an array type is Object." > > http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getSuperclass() > > "If this object represents an array class then the Class object > representing the Object class is returned." If we keep repeating the information enough, eventually it will get through. It certainly is mentioned in enough places in the JLS:
<http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.10.3>
> 4.10.3 Subtyping among Array Types > The following rules define the direct subtype relation among array types: [quoted text clipped - 7 lines] > o Cloneable >1 p[] > o java.io.Serializable >1 p[] /op. cit./, /supra/.
 Signature Lew
Mike Schilling - 07 Mar 2008 07:12 GMT >> Mike Schilling wrote: >> .... [quoted text clipped - 14 lines] > 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. :-)
Lew - 07 Mar 2008 12:41 GMT > 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.
 Signature Lew
Mike Schilling - 07 Mar 2008 16:13 GMT >> 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. OK, say "defines" instead of "has", if you want to be a stickler.
Andreas Leitgeb - 06 Mar 2008 18:45 GMT > ... >>> In what ways are arrays not objects? >> >> Don't know, if that's what Daniel meant, but arrays are not >> accessed through get-/putfield or invoke... opcodes, but >> through <x>aload/<x>astore opcodes for <x> any of [abcdfils].
> That is an implementation detail in compilers that target bytecode, not > a Java language feature. Well there is special syntax for arrays, that cannot be mimicked by objects... but then, this is also true for enums and collections... Nah! let's stop this hairsplitting :-)
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|