Java は決して参照渡しではありませんよね?…そうですよね?[重複]
-
18-09-2019 - |
質問
重複の可能性:
Java は「参照渡し」ですか?
今日、珍しい Java メソッドを見つけました。
private void addShortenedName(ArrayList<String> voiceSetList, String vsName)
{
if (null == vsName)
vsName = "";
else
vsName = vsName.trim();
String shortenedVoiceSetName = vsName.substring(0, Math.min(8, vsName.length()));
//SCR10638 - Prevent export of empty rows.
if (shortenedVoiceSetName.length() > 0)
{
if (!voiceSetList.contains("#" + shortenedVoiceSetName))
voiceSetList.add("#" + shortenedVoiceSetName);
}
}
変数、複雑なオブジェクトを渡すときの Java の動作について私が読んだすべてによると、このコードはまったく何もしないはずです。それで、うーん...ここで何かが足りないでしょうか?私が忘れてしまった微妙な点があるのでしょうか、それともこのコードは thedailywtf に属しているのでしょうか?
解決
Rytmis 氏が述べたように、Java は参照を値で渡します。これが意味するのは、メソッドのパラメータに対して変更メソッドを正当に呼び出すことはできますが、それらを再割り当てして値の伝播を期待することはできないということです。
例:
private void goodChangeDog(Dog dog) {
dog.setColor(Color.BLACK); // works as expected!
}
private void badChangeDog(Dog dog) {
dog = new StBernard(); // compiles, but has no effect outside the method
}
編集: この場合、これが意味するのは、 voiceSetList
かもしれない このメソッドの結果として変更される (新しい要素が追加される可能性があります)。 vsName
メソッドの外部では表示されません。混乱を避けるために、私はメソッドのパラメータにマークを付けることがよくあります final
, これにより、メソッド内で (偶然かどうかにかかわらず) 再割り当てが行われないようになります。これにより、2 番目の例はまったくコンパイルできなくなります。
他のヒント
Javaパス 値による参照, したがって、参照のコピーを取得しますが、参照されるオブジェクトは同じです。したがって、このメソッドは入力リストを変更します。
参照自体は値によって渡されます。
Deitel & Deitel 著『Java How to Program 第 4 版』より:(ページ329)
他の言語とは異なり、Javaでは、プログラマーが各引数を値ごとに渡すか、参照で渡すかを選択することはできません。プリミティブデータ型変数は常に値で渡されます。オブジェクトはメソッドには渡されません。むしろ、オブジェクトへの参照はメソッドに渡されます。参照自体は値渡しされ、参照のコピーが渡されます をメソッドに追加します。メソッドがオブジェクトへの参照を受け取ると、メソッドは オブジェクトを直接取得します。
大学でJavaを学ぶ際にこの本を利用しました。素晴らしい参考資料です。
それを説明した良い記事があります。http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html
まあ、それは操作できます ArrayList
- これはオブジェクトです...オブジェクト参照を渡している場合 (値によって渡された場合でも)、そのオブジェクトへの変更は呼び出し元に反映されます。それが質問ですか?
vsNameが変更されているので混乱していると思います。ただし、この文脈では、これは shortedVoiceSetName とまったく同じレベルの単なるローカル変数です。
コード内の正確な質問が何であるかはわかりません。Java は値渡しですが、配列はオブジェクトを渡さずポインタのみを渡すため、参照渡しです。配列は実際のオブジェクトではなくポインターで構成されます。これにより、非常に速くなりますが、扱うのが危険になります。これを解決するには、それらをクローンしてコピーを取得する必要がありますが、その場合でも配列の最初の次元のみがクローンされます。
詳細については、ここでの私の回答を参照してください。 Java では、浅いコピーとは何ですか? (私の他の回答も参照してください)
ちなみに、配列は単なるポインターであるため、いくつかの利点があります。それらを同期オブジェクトとして(絶対)使用できます。