実際のところ、Java は値渡しです。ただし、「参照による配列」もあります。そのため、Java はオブジェクト (少なくとも配列) の場合は参照渡しであり、プリミティブの場合は値渡しのみであると多くの人が考えています。
ここに短いテストがあります:
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]);
複製するか = を使用するかに関係なく、System.out.print は常に次のようになります。
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
これは、クローンと配列が有害な組み合わせであることを証明しています。なぜなら、配列はポインタしか格納しないからです! これが配列のないオブジェクトにも当てはまるかどうかをテストする必要があります...これは、Javaが常に「参照によるストレージ」であることを意味するためです(そして、「クローン」機能は、オブジェクトにとって悪い冗談にすぎません)プリミティブのみが実際の値であり、参照はありません!
そして、ロジックについて知っているので: storage-by-reference x pass-by-value == "storage-by-value x pass-by-reference" (オブジェクトの場合!)、
学校からすでに知っていましたが、値によるストレージ x 値による受け渡し (プリミティブの場合)
では、私たちは皆、プログラミングの教師に (大学でも) 嘘をつかれたのでしょうか? たぶん、しかし彼らは少なくとも論理的な誤りを犯していませんでした...だからそれは嘘ではなく、ただ間違っていました.
編集
上記と同じコードをクラスで書きました。最初にデータ構造です。
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;
}
}
}
今コントローラー:
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());
= または 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
これで、すべてのオブジェクトをすぐに支配できる「マスター アレイ」をポケットに入れました。(これは本当に良いことではありません)
私はいつも Java 配列に不安を感じていましたが、それが何であるかは言えませんでした。それ以来、配列はオブジェクトのコンテナーとしてしか使用していなかったので、気分が良くなりました... PHP などのスクリプト言語での配列の重要性に非常に驚いています。
それでも、Java 配列は、簡単に渡して共有値にアクセスできるため、スレッド間の同期に最適です。しかし、PHP や C++ などの出身のプログラマーは、実際に Java 配列でいくつかの問題を経験する可能性があります。;D
ああ、私はこの記事が好きです: http://javadude.com/articles/passbyvalue.htm
更新:配列を含むオブジェクトをコピーするための優れたソリューションを見つけました。ここで私の解説を参照してください: Object.clone() の使用におけるバグ