Javaは参照渡しですか、それとも値渡しですか?

多くのプログラミング言語では、参照または値によってパラメーターを渡すことができます。Javaでは、値でのみパラメータ渡すことができます。これにはいくつかの制限があり、疑問も生じます。たとえば、メソッドでパラメータ値が変更された場合、メソッド実行後の値はどうなりますか?また、Javaがメモリヒープ内のオブジェクト値をどのように管理するのか不思議に思うかもしれません。このJavaチャレンジャーは、Javaのオブジェクト参照に関するこれらの質問やその他の一般的な質問を解決するのに役立ちます。

ソースコードを入手する

このJavaチャレンジャーのコードを入手してください。例に従いながら、独自のテストを実行できます。

オブジェクト参照は値で渡されます

Javaのすべてのオブジェクト参照は、値によって渡されます。これは、値のコピーがメソッドに渡されることを意味します。ただし、コツは、値のコピーを渡すと、オブジェクトの実際の値も変更されることです。理由を理解するには、次の例から始めます。

 public class ObjectReferenceExample { public static void main(String... doYourBest) { Simpson simpson = new Simpson(); transformIntoHomer(simpson); System.out.println(simpson.name); } static void transformIntoHomer(Simpson simpson) { simpson.name = "Homer"; } } class Simpson { String name; } 

メソッドが実行されたsimpson.name後はどうなると思いますtransformIntoHomerか?

この場合、それはホーマーになります!その理由は、Javaオブジェクト変数は、メモリヒープ内の実際のオブジェクトを指す単なる参照であるためです。したがって、Javaがパラメータを値でメソッドに渡しても、変数がオブジェクト参照を指している場合は、実際のオブジェクトも変更されます。

これがどのように機能するかまだはっきりしない場合は、下の図を見てください。

ラファエル・チネラート・デル・ネロ

プリミティブ型は値によって渡されますか?

オブジェクト型と同様に、プリミティブ型も値によって渡されます。次のコード例で、プリミティブ型がどうなるかを推測できますか?

 public class PrimitiveByValueExample { public static void main(String... primitiveByValue) { int homerAge = 30; changeHomerAge(homerAge); System.out.println(homerAge); } static void changeHomerAge(int homerAge) { homerAge = 35; } } 

値が30に変わると判断した場合は、正解です。(再び)Javaがオブジェクトパラメータを値で渡すため、30です。数値30は値の単なるコピーであり、実際の値ではありません。プリミティブ型はスタックメモリに割り当てられるため、ローカル値のみが変更されます。この場合、オブジェクト参照はありません。

不変のオブジェクト参照を渡す

不変Stringオブジェクトで同じテストを行った場合はどうなりますか?

JDKには、多くの不変のクラスが含まれています。例としては、ラッパーの種類が含まれIntegerDoubleFloatLongBooleanBigDecimal、そしてもちろん、非常によく知られているStringクラス。

次の例では、の値を変更するとどうなるかに注目してくださいString

 public class StringValueChange { public static void main(String... doYourBest) { String name = ""; changeToHomer(name); System.out.println(name); } static void changeToHomer(String name) { name = "Homer"; } } 

出力はどうなると思いますか?「」を推測した場合は、おめでとうございます。これは、Stringオブジェクトが不変であるために発生します。つまり、内部のフィールドStringは最終的なものであり、変更することはできません。

作るStringクラス不変することは私たちにJavaの最も使用されるオブジェクトのいずれかをより良く制御することができます。aの値をString変更できると、多くのバグが発生します。また、Stringクラスの属性は変更しないことに注意してください。代わりに、単に新しいString値を割り当てています。この場合、「ホーマー」値に渡されるnamechangeToHomer方法。String「ホーマーは」とゴミはすぐとして収集の対象となりますchangeToHomerメソッドが実行を完了します。オブジェクトは変更できませんが、ローカル変数は変更されます。

文字列など

JavaのStringクラスなどの詳細:JavaチャレンジャーシリーズのRafaelの投稿をすべて参照してください。

可変オブジェクト参照の受け渡し

とは異なりString、JDKのほとんどのオブジェクトは、StringBuilderクラスのように変更可能です。以下の例は前の例と似ていますが、機能StringBuilderではなくString

 static class MutableObjectReference { public static void main(String... mutableObjectExample) { StringBuilder name = new StringBuilder("Homer "); addSureName(name); System.out.println(name); } static void addSureName(StringBuilder name) { name.append("Simpson"); } } 

この例の出力を推測できますか?この場合、可変オブジェクトを使用しているため、出力は「ホーマーシンプソン」になります。Javaの他の可変オブジェクトからも同じ動作が期待できます。

Java変数は値によって渡されること、つまり値のコピーが渡されることをすでに学習しました。コピーされた値は、Javaメモリヒープ内の実際のオブジェクトを指していることに注意してください。値を渡すと、実際のオブジェクトの値が変わります。

オブジェクト参照に挑戦してください!

このJavaチャレンジャーでは、オブジェクト参照について学んだことをテストします。以下のコード例では、不変クラスStringと可変StringBuilderクラスが表示されます。それぞれがパラメータとしてメソッドに渡されています。Javaは値のみを渡すことを知っているので、このクラスのmainメソッドが実行されると、何が出力になると思いますか?

 public class DragonWarriorReferenceChallenger { public static void main(String... doYourBest) { StringBuilder warriorProfession = new StringBuilder("Dragon "); String warriorWeapon = "Sword "; changeWarriorClass(warriorProfession, warriorWeapon); System.out.println("Warrior=" + warriorProfession + " Weapon=" + warriorWeapon); } static void changeWarriorClass(StringBuilder warriorProfession, String weapon) { warriorProfession.append("Knight"); weapon = "Dragon " + weapon; weapon = null; warriorProfession = null; } } 

オプションは次のとおりです。この記事の最後で回答キーを確認してください。

A:Warrior = null Weapon = null

B:ウォリアー=ドラゴンウェポン=ドラゴン

C:ウォリアー=ドラゴンナイトウェポン=ドラゴンソード

D:ウォリアー=ドラゴンナイトウェポン=ソード

何が起こったのですか?

上記の例の最初のパラメーターはwarriorProfession変数であり、これは可変オブジェクトです。2番目のパラメーターであるweaponは不変Stringです:

 static void changeWarriorClass(StringBuilder warriorProfession, String weapon) { ... } 

それでは、このメソッド内で何が起こっているのかを分析しましょう。このメソッドの最初の行でKnightwarriorProfession変数に値を追加します。これwarriorProfessionは可変オブジェクトであることを忘れないでください。したがって、実際のオブジェクトが変更され、そこからの値は「ドラゴンナイト」になります。

 warriorProfession.append("Knight"); 

2番目の命令では、不変のローカルString変数が「ドラゴンソード」に変更されます。ただし、Stringは不変であり、その属性は最終的なものであるため、実際のオブジェクトは変更されません。

 weapon = "Dragon " + weapon; 

最後に、nullここで変数に渡しますが、オブジェクトには渡しません。オブジェクトは、外部からアクセスできる限り(この場合はmainメソッドを介して)同じままです。また、ローカル変数はnullになりますが、オブジェクトには何も起こりません。

 weapon = null; warriorProfession = null; 

これらすべてから、可変StringBuilderおよび不変の最終値Stringは次のようになると結論付けることができます。

 System.out.println("Warrior=" + warriorProfession + " Weapon=" + warriorWeapon); 

changeWarriorClassメソッドで変更された唯一の値はwarriorProfession、可変StringBuilderオブジェクトであるためです。warriorWeapon不変Stringオブジェクトであるため、変更されていないことに注意してください。

チャレンジャーコードからの正しい出力は次のとおりです。

D:ウォリアー=ドラゴンナイトウェポン=ソード。

ビデオチャレンジ!Javaでのオブジェクト参照のデバッグ

デバッグは、コードを改善しながらプログラミングの概念を完全に吸収する最も簡単な方法の1つです。このビデオでは、Javaでオブジェクト参照をデバッグおよび説明している間、フォローすることができます。

オブジェクト参照に関するよくある間違い

  • 参照によって不変の値を変更しようとしています。
  • 参照によってプリミティブ変数を変更しようとしています。
  • Expecting the real object won't change when you change a mutable object parameter in a method.

What to remember about object references

  • Java always passes parameter variables by value.
  • Object variables in Java always point to the real object in the memory heap.
  • A mutable object’s value can be changed when it is passed to a method.
  • An immutable object’s value cannot be changed, even if it is passed a new value.
  • “Passing by value” refers to passing a copy of the value.
  • “Passing by reference” refers to passing the real reference of the variable in memory.

Learn more about Java

  • Get more quick code tips: Read all of Rafael's posts in the JavaWorld Java Challengers series.
  • Learn more about mutable and immutable Java objects (such as String and StringBuffer) and how to use them in your code.
  • Javaのプリミティブ型が物議を醸していることを知って驚くかもしれません。この機能では、John I. Mooreが、それらを保持し、それらを上手に使用することを学ぶことを主張します。
  • Java DevGymでJavaプログラミングスキルを構築し続けてください。
  • Java継承のデバッグが好きな場合は、RafaelのJavaチャレンジビデオプレイリストで他のビデオをチェックしてください(このシリーズのビデオはJavaWorldと提携していません)。
  • ストレスのないプロジェクトに取り組み、バグのないコードを書きたいですか?No BugsProjectにアクセスして、バグなし、ストレスなしのコピーを入手してください-人生を破壊することなく人生を変えるソフトウェアを作成してください

この話、「Javaは参照渡しですか、それとも値渡しですか?」もともとJavaWorldによって公開されました。