As a matter of fact, Java is pass-by-value. But it also has "arrays-by-reference"! That's why many people think Java is pass-by-reference for objects (at least for arrays) and only pass-by-values for primitives.
Here is a short test:
String[] array = new String[10];
array[0] = "111";
ArrayList one = new ArrayList();
one.add(array);
ArrayList two = (ArrayList) one.clone(); //Alternate with: ArrayList two = one;
String[] stringarray1 = (String[]) one.get(0);
String[] stringarray2 = (String[]) two.get(0);
System.out.println("Array: "+one+" with value: "+stringarray1[0]);
System.out.println("Array: "+one+" with value: "+stringarray2[0]);
array[0] = "999";
String[] stringarray3 = (String[]) one.get(0);
String[] stringarray4 = (String[]) two.get(0);
System.out.println("Array: "+one+" with value: "+stringarray3[0]);
System.out.println("Array: "+two+" with value: "+stringarray4[0]);
No matter if you clone or use =, the System.out.print will always look like this:
Array: [[Ljava.lang.String;@addbf1] with value: 111
Array: [[Ljava.lang.String;@addbf1] with value: 111
Array: [[Ljava.lang.String;@addbf1] with value: 999
Array: [[Ljava.lang.String;@addbf1] with value: 999
This proves that cloning and arrays are a harmful combination, because arrays only store pointers! I still need to test if this is also true for no-array objects...because this would mean that Java is always "storage-by-reference" (and the "clone"-function would be only a bad joke for any objects containing arrays), while only primitives are real values and no references!
And since we know about logic: storage-by-reference x pass-by-value == "storage by value x pass-by-reference" (for objects!),
while we already knew since school: storage-by-value x pass-by-value (for primitives)
So, were we all lied to by our programming teachers (even at university)? Maybe, but they didn't make any logical errors at least...so it wasn't a lie, it was just wrong.
EDIT
I wrote the same code as above with a class, first the data structure:
public class Foobar implements Cloneable {
String[] array;
public Foobar() {
this.array = new String[10];
}
public String getValue(){
return array[0];
}
public String[] getArray(){
return array;
}
public void setArray(String[] array){
this.array = array;
}
@Override
public Object clone(){
try{
Foobar foobar = (Foobar) super.clone();
foobar.setArray(array);
return foobar;
}
catch(Exception e){
return null;
}
}
}
Now the controller:
String[] array = new String[10];
array[0] = "111";
Foobar foo1 = new Foobar();
foo1.setArray(array);
Foobar foo2 = foo1; //Alternation: Foobar foo2 = (Foobar) foo1.clone();
System.out.println("Instance: "+foo1.getArray()+" with value: "+foo1.getValue());
System.out.println("Instance: "+foo2.getArray()+" with value: "+foo2.getValue());
array[0] = "999";
System.out.println("Instance: "+foo1.getArray()+" with value: "+foo1.getValue());
System.out.println("Instance: "+foo2.getArray()+" with value: "+foo2.getValue());
The test results will always look like that - no matter if I use = or clone():
Instance: [Ljava.lang.String;@42e816 with value: 111
Instance: [Ljava.lang.String;@42e816 with value: 111
Instance: [Ljava.lang.String;@42e816 with value: 999
Instance: [Ljava.lang.String;@42e816 with value: 999
Now I've got the "master array" in the pocket, with whom I can rule all objects right away! (which isn't really a good thing)
I always felt uneasy about Java arrays, but I couldn't say what it was. Now I know it, and I feel good since I only used arrays as container for objects ever since...only to find myself being quite surprised how important they are in script languages like PHP!
Still, Java arrays are great for synchronisation between threads, as you can pass them easily and still access shared values. But programmers coming from PHP or C++ or somewhere else may indeed experience some problems with Java arrays. ;D
Oh, I like this article: http://javadude.com/articles/passbyvalue.htm
UPDATE: I've found a great solution to copy any object containing arrays, see my commentary here: Bug in using Object.clone()