File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes System.arraycopy() or clone(). Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "System.arraycopy() or clone()." Watch "System.arraycopy() or clone()." New topic
Author

System.arraycopy() or clone().

Vlad Rabkin
Ranch Hand

Joined: Jul 07, 2003
Posts: 555
Hi,
Could anyone help me to understand what is better?
As a sample I will provide a DataInfo class constructor from FBN:

or this:

I personally like clone() better, but I don't know if there are tricks by clone(), which should prevent me for using it here?
Using a clone makes all thing a bit eleganter. For example:


Any comments?
Tx,
Vlad
Sathya Sankar
Ranch Hand

Joined: Sep 16, 2000
Posts: 67
Hi Vlad,
The clone method, creates new instances of the object/array to be cloned and sets the instance variables values/references for the new object the same as that of the original object. Whereas System.arraycopy does not create new objects but only copies the reference of the source array element by element and assigns them to the destination array.
So your choice would depend on the requirement of whether at the end of the operation you want 2 independent arrays - clone method or just 2 copies of the same array (so if you modify one the other too will be modified) - System.arraycopy.
Ciao,
GSS


SCJP, SCJD, SCWCD 1.3, SCWCD 1.4, SCBCD
Vlad Rabkin
Ranch Hand

Joined: Jul 07, 2003
Posts: 555
Hi Sathya,

The clone method, creates new instances of the object/array to be cloned and sets the instance variables values/references for the new object the same as that of the original object. Whereas System.arraycopy does not create new objects but only copies the reference of the source array element by element and assigns them to the destination array.


I disagree. Both clone() and System.arraycopy create new array and BOTH copy just references to another array. So in both cases only array is new created, but not its elements!!!
Here is an example:


And here is result:

As you see the references to the element in array was is the same in both cases: clone() and System.arraycopy().
Vlad
Vlad Rabkin
Ranch Hand

Joined: Jul 07, 2003
Posts: 555
Hi,
I have made performca test:

Results:

So, System.arraycopy() is a bit faster. I have found some links saying that by cloning an array only shallow clone is performed. I don't know what shallow clone means. The only think, which I undderstand is that by cloning only one dimensional object arrays would work, but it is Ok, since we have one-dimensional array.
So, the only real difference is that clone() works a BIT slower, but is much easier.
Am I right?
Tx,
Vlad
P.S. It seems that I am discussing the issue with myself
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
I think that clone() does exactly the same thing as your arraycopy() code, and is a little shorter, and thusmore elegant. In fact you don't need

because the clone() is just going to overwrite this.fields with a new FieldInfo[] array.
In general, you have to look carefully at the fields you're dealing with, and decide if a shallow copy is really appropriate. But for an array of immutable objects like Strings, there's no benefit to making a deep copy, so any time I want a copy of a String[] array I just use clone(). Fast and easy.
BTW for this specific class it's not clear to me why you need to clone the FieldInfo[] at all. It's not difficult to set up an immutable DBMetaData class. To make it immutable, you can't expose internal arrays - but you can have methods like getFieldName(int index) and getFieldLength(int index). Once the metadata is represented as an immutable object, there's no need to clone it at all. You just create one instance when the DB file is first loaded, and after than just keep passing around references to that one object, which is essentially a singleton. Well, multiton really, one per DB file. (You're not expecting anyone to edit the DB header info while you're running, right?) It's not really clear to me why DataInfo needs its metadata, but even if it does, it certainly doesn't need private copies of everything. A reference to a shared immutable DBMetaData instance ought to suffice, IMO.
Cheers...


"I'm not back." - Bill Harding, Twister
Vlad Rabkin
Ranch Hand

Joined: Jul 07, 2003
Posts: 555
Hi Jim,
and decide if a shallow copy is really appropriate

Could you please explain, whatdoe it mean "shallow copy".
is it that no new objects are create, just references copied from one array to another?
BTW for this specific class it's not clear to me why you need to clone the FieldInfo[] at all

It was just sample. It has no meaning.
I don't clone MetaData.

I have URLyBird. Its interface is pterry the same as in yours assignement.
The problem there how could you make your client flexible (it is required) using such signature String[] read (int recNo);
You need an object like DataInfo containing data (String[] values) and Field info (FieldInfo[] field) to be able to find out connection value-field.
Moreover, you are right about FieldInfo, but String value must be cloned, since I want DataInfo to provide methods setValue(columnName, String value), to make the client feels request object correctly!?

Best,
Vlad
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
Hi, V!
Could you please explain, whatdoe it mean "shallow copy".
is it that no new objects are create, just references copied from one array to another?

Yes, that's it. The clone() method does shallow copying only, so if you want a deep copy, you have to do it yourself. For a complex data structure, there may be a question of "how deep?" - you may want to create new instances of some things, and just copy references for others.
The problem there how could you make your client flexible (it is required) using such signature String[] read (int recNo);
You need an object like DataInfo containing data (String[] values) and Field info (FieldInfo[] field) to be able to find out connection value-field.

I agree that for a flexible client you need to have metadata like this available. I just don't think each separate record row needs its own copy of this metadata; in my design, a client calls getMetaData() to get a single DBMetaData object from the server. This object is saved in an instance field on the client, and anytime it needs to access metadata, it just accesses that same instance.
Moreover, you are right about FieldInfo, but String value must be cloned, since I want DataInfo to provide methods setValue(columnName, String value), to make the client feels request object correctly!?
OK, if you provide set methods, you should clone to ensure that the original is not corrupted by outside code. Agreed. I avoided set methods since I didn't see any reason anyone should change any metadata attributes after creation. My metadata class constructor accepts a file name for the DB file it represents; it reads the header from that file in the constructor, and thus it's able to set all its fields in that constructor, and there's no need for any set methods after that. I tend to make variables final, and classes immutable, whenever possible. Cuts down on things I have to worry about later, such as thread safety.
Interesting to see your results on the performance of clone() vs. arraycopy(). That's kind of annoying; I hate it when the elegant solution isn't also the most efficient. Hopefully they may be able to improve this in future releases. I experimented some more, and found that the performance difference is most notable for short arrays. If you clone an array with a hundred elements or so, there's virtually no difference in performance. So it seems the performance hit for clone() is a one-time thing. My guess is it's because clone() uses some reflection to decide what class it's instantiating. there's also a minor cost to casting the array to the appropriate type, but testing shows this is no big deal - you can make it go away by treating the clone as an Oject, and yet the performance is virtually unchanged. So I really think it's the reflection that's the issue here.
Regardless, I plan to continue to use clone() except in cases where I have established clone() is actually a performance bottleneck, as I still believe it's clearer in most cases.
Good discussion topic. Cheers...
Vlad Rabkin
Ranch Hand

Joined: Jul 07, 2003
Posts: 555
Hi Jim,

I just don't think each separate record row needs its own copy of this metadata; in my design, a client calls getMetaData() to get a single DBMetaData object from the server.
...
I avoided set methods since I didn't see any reason anyone should change any metadata attributes after creation.

Your choise is much simpler to implement and understand. The only problem is that your server MUST trust the client: That is server must trust that client really used MetaData to feel array of String. If the client
has filled String[] incorrectly, your server has no chances to detect if let's say String[0] is really name value, String[1] is location value an so on, but may you are right, I am doing everything to complicated ...

If you clone an array with a hundred elements or so, there's virtually no difference in performance

I have found an article, which says that performance is not really guaranteed. There some cases where you own for loop with "deep" copy can be faster, than even System.arraycopy()!

Regardless, I plan to continue to use clone() except in cases where I have established clone() is actually a performance bottleneck, as I still believe it's clearer in most cases.

Agreed!
Tx for supporting this discussion!
Vlad
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
I have found an article, which says that performance is not really guaranteed. There some cases where you own for loop with "deep" copy can be faster, than even System.arraycopy()!
Hmmm... I'd be interested in seeing a link to that article, as I have a hard time imagining that offhand, assuming all other things are equal (e.g. no change of platfrom mid-test). But yeah, there are probably exceptions somewhere; there usually are where performance is concerned. I expect my statements are true in general though.
Vlad Rabkin
Ranch Hand

Joined: Jul 07, 2003
Posts: 555
Hi Jim,
Here is the link:
Article

Some consider System.arraycopy to have the best performance, but an example run shows that this conclusion may not always be correct :
>java -cp . ArrayCopier performance 250000
Using clone: 360 ms
Using System.arraycopy: 181 ms
Using for loop: 150 ms

Best,
Vlad
Vlad Rabkin
Ranch Hand

Joined: Jul 07, 2003
Posts: 555
Hi Jim,
I am just think all the time about your statement:

I just don't think each separate record row needs its own copy of this metadata; in my design, a client calls getMetaData() to get a single DBMetaData object from the server. This object is saved in an instance field on the client, and anytime it needs to access metadata, it just accesses that same instance.

I know that you use indexes, but imagine that field names are used to identify value.
I just wrote pseudo-code for book method of GUIController:

So if your client doesn't do the loop to create String[] record for request
(in the right order), the server has no way to validate the right order of elements in arrays and it could save wrong data in the file!
I mean, we can say it is Ok for the assignement, but may be I understood you not correctly and you have managed to make sure the order of values in String[] send by client is correct?
If so, can you give any idea?
Tx,
Vlad
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
Hi Jim,
I know that you use indexes, but imagine that field names are used to identify value.
Yes, but only on startup. I create an int[] which maps table colum index to DB field index. This int[] array is initialized by looking up the expected String name of each of the 6 columns, and an error is thrown if it can't be initialized because the metadata doesn't have all required columns. (It's OK if there are extra columns or they're not in the usual order.) After initialization, the db column names are never used again; only the int[] array is subsequently used to convert between DB columns and table columns.
So if your client doesn't do the loop to create String[] record for request (in the right order), the server has no way to validate the right order of elements in arrays and it could save wrong data in the file!
True, this design places a certain amount of trust in the client. My server is very generic; it accepts just about any String in any column. The only validation it know how to perform is to check if the string is too long. All other business logic is client-side. Thiis makes the server reusable for other things, but it isn't great for protecting DB integrity. A real-world system would probably want a middle tier on the server, to implement business logic including validations. However I wanted to keep things simple, and my interpretation of the specs for locking indicated that at least some low-level functions (like dealing with cookies) need to be done on the client, and maybe they wanted the entire DB interface exported to the client. So I chose to make the client-server interface look exactly like the DB interface required for "data access" (once you wrap the Remote object in an adapter which catches any RemoteException). Given this setup, there wasn't much room for additional logic on the server, as the API the server was implementing was very generic; no business logic. So, all my business-specific logic is on the client, including validation. If someone writes bad client code, they can screw up the server - but that was true the moment Sun required that the client be able to use the lock() method. Once I trust the client code that much, I might as well trust it all the way and keep things simple and put all the validation in one place, on the client. Again, that's not so great for a robust commercial product, but it's fine IMO for the simple requirements we've been given, considering the silly design they've forced on us.
Cheers...
Sathya Sankar
Ranch Hand

Joined: Sep 16, 2000
Posts: 67
Hi Vlad,
A lot of discussion has taken place on this while I was merrily sleeping . Just wanted to clarify when I said System.arraycopy does not create new objects.
I disagree. Both clone() and System.arraycopy create new array and BOTH copy just references to another array. So in both cases only array is new created, but not its elements!!!

No. System.arraycopy DOES NOT create a new array. Instead it expects the caller to pass a destination array of valid size.
For eg.
Will throw a NullPointerException because d2 is null.
However, the same code will work if d2 is created with d2 = new Date[2] before the call to System.arraycopy.
Ciao,
GSS
So in both cases the new objects get created eventually - For System.arraycopy the user has to create it and pass the reference to the method as the method will not create the array of required size. While for clone, the new object gets created by the clone operation.
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
[GSS]: System.arraycopy DOES NOT create a new array.
Agreed. I didn't notice this in Vlad's quote earlier.
[Vlad]: I have found an article, which says that performance is not really guaranteed. There some cases where you own for loop with "deep" copy can be faster, than even System.arraycopy()!
From the article you showed, in the code they used to demonstrate that arraycopy() is not always fastest, the for loop does not really do a "deep" copy since the data are just ints - there's no difference between deep and shallow here, so clone() is just as "deep" as the for loop in this case. I also note that the array they're copying only has ten elements, even if the copying is repeated 250000 times. I suspect that arraycopy() has a slightly higher one-time overhead due to the fact that the arguments are simply Object type; there's probably some extra work being done to figure out what type of arrays are really involved. So a for loop can be faster on short arrays; the arraycopy will probably win on longer arrays. (Though again, no guarantees.) Cheers...
Vlad Rabkin
Ranch Hand

Joined: Jul 07, 2003
Posts: 555
Hi Gss and Jim,

Yes, agreed, but I was comparing (you can see it my example), clone() and
this block, not just System.arrycopy().
Whatever, the point is that we all agree on the idea.
Tx,
Vlad
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
Whatever, the point is that we all agree on the idea.
No, no! The point is, Max is leaving us, so now we need to find new people to argue with. Your sensible conciliatory attitude is not helpful here.
Vlad Rabkin
Ranch Hand

Joined: Jul 07, 2003
Posts: 555
Hi Jim,
we need to find new people to argue with


But we shouldn't scare these canditates on the start. We have first to show that sometimes we can agree.
The purpose to argue something is strong beileve to achieve an agreement(otherwise there is no sense to argue), which actually never happens...
Beleive me, I have tried it many times with my wife
Best,
Vlad
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: System.arraycopy() or clone().