方法 - java 参照渡し 配列




Javaは「参照渡し」または「渡し渡し」ですか? (20)

私はいつもJavaが参照渡しであると思っていました。

しかし、私はそれがそうでないと主張するいくつかのブログ投稿(例えば、 このブログ )を見ました。

彼らが何をしているのか分かりません。

説明は何ですか?


参照は、使用する言語にかかわらず、常に表現された値です。

ボックスビューの外側を見るには、アセンブリや低レベルのメモリ管理を見てみましょう。CPUレベルでは、何かへの参照は、メモリまたはCPUレジスタの1つに書き込まれるとすぐにになります。(そのため、ポインタは良い定義であり、同時に目的を持つ値です)。

メモリ内のデータにはLocationがあり、その場所には値(バイト、ワードなど)があります。アセンブリでは、特定の場所(別名変数)に名前を付ける便利なソリューションがありますが、コードをコンパイルするときに、ブラウザがドメイン名をIPアドレスに置き換えるように、アセンブラは名前を指定された場所に置き換えます。

コアに至るまで、言語を表現することなく(何かがすぐに値になったとき)何かの言葉に参照を渡すことは技術的に不可能です。

変数Fooがあり、Locationがメモリ内の47番目のバイトにあり、Valueが5であるとします。メモリ内の223番目のバイトにある別の変数Ref2Fooがあり、その値は47です。このRef2Fooは技術変数プログラムによって明示的に作成されたものではありません。他の情報なしで5と47だけを見ると、2つのが表示されます。あなたが参照としてそれらを使用して到達する5には、私たちは旅行する必要があります:

(Name)[Location] -> [Value at the Location]
---------------------
(Ref2Foo)[223]  -> 47
(Foo)[47]       -> 5

これがジャンプテーブルの仕組みです。

Fooの値を持つメソッド/関数/プロシージャを呼び出す場合は、言語といくつかのメソッド呼び出しモードに応じて、変数をメソッドに渡す方法がいくつかあります。

  1. 5がCPUレジスタの1つ(EAX)にコピーされます。
  2. 5はスタックにPUSHdを取得します。
  3. 47はCPUレジスタの1つにコピーされます
  4. 47スタックにプッシュします。
  5. 223がCPUレジスタの1つにコピーされます。
  6. 223はスタックにPUSHdを取得します。

上記の値(既存の値のコピー)を上回るすべてのケースで、それを処理する受信メソッドまで追加されました。メソッドの中に "Foo"を書くと、EAXから読み込まれるか、自動的に逆参照されるか、または二重逆参照されます。プロセスは言語の仕方やFooのタイプによって異なります。逆参照プロセスを回避するまで、これは開発者から隠されています。そう基準は、あるの基準は、(言語レベルで)処理されなければならない値であるため、表現します、。

今我々はメソッドにFooを渡しました:

  • Foo(Foo = 9)を変更した場合、値のコピーがあるのでローカルスコープにのみ影響します。このメソッドの内部から、元のFooがどこにあるのかを判断することさえできません。
  • ケース3と4の場合、デフォルトの言語構成を使用してFoo(Foo = 11)を変更すると、Fooはグローバルに変更される可能性があります(JavaやPascalのprocedure findMin(x, y, z: integer; var mの ような言語に依存します: integer);)。しかし、言語があなたが参照解除プロセスを回避することを可能にするならば、あなたは47言い換えることができます49。その時点で、ローカルポインタを変更したため、Fooはそれを読めば変更されたように見えます。このFooをメソッドの中で修正する場合Foo = 12は、プログラムの実行を別のメモリに書き込むことになるので、おそらくプログラムの実行をFUBARします。実行可能ファイルを保持することを目的とした領域も変更できますそれを書くと実行中のコードが変更されます(Fooは現在ではありません47)。しかし、Fooの価値47メソッド47のコピーでもあったため、メソッド内のものだけがグローバルに変更されませんでした。
  • 5.と6.の場合223、メソッド内で変更すると、3.や4.と同じ問題が発生します(今度はポインタとして使用され、ポインタとして再び使用されます)が、これはまだローカルです問題は、223がコピーされたためです。あなたが逆参照することができます場合はRef2Foo(つまり223)に到達し、先の尖った値を変更47するために、たとえば、49それがfooに影響を与えますグローバルこの場合には方法がのコピーを得たので、223しかし、参照47一度だけ存在し、ことを変更49すべてのRef2Foo二重逆参照を間違った値に導くことになります。

重要ではない細部、たとえ参照渡しの言語でさえ、関数に値を渡しますが、それらの関数は逆参照の目的で値を使用しなければならないことを知っています。この値渡しは、実際には役に立たず、用語が参照渡しでしかないため、プログラマから隠されているだけです。

厳密な値渡しも無用です。つまり、配列を引数としてメソッドを呼び出すたびに100Mバイトの配列をコピーする必要があります。そのため、Javaは厳密に値渡しできません。すべての言語は、この巨大な配列への参照を(値として)渡し、その配列がメソッド内でローカルに変更できる場合はコピーオンライトメカニズムを使用します(Javaのように)メソッドをグローバルに(呼び出し側のビュー)、いくつかの言語では参照自体の値を変更することができます。

だから、短いとJavaの独自の用語ではでは、Javaはある値渡し値は次のいずれかをすることができ、実際の値またはの表現である参照


Javaでは常に、引数は値渡しで、参照渡しではありません。

これをexampleを使って説明しましょう:

public class Main{
     public static void main(String[] args){
          Foo f = new Foo("f");
          changeReference(f); // It won't change the reference!
          modifyReference(f); // It will modify the object that the reference variable "f" refers to!
     }
     public static void changeReference(Foo a){
          Foo b = new Foo("b");
          a = b;
     }
     public static void modifyReference(Foo c){
          c.setAttribute("c");
     }
}

私はこれを段階的に説明します:

  1. Foo型のfという名前の参照を宣言し、それを属性"f"持つFoo型の新しいオブジェクトに割り当てます。

    Foo f = new Foo("f");
    

  2. メソッド側から、名前がa Foo型の参照が宣言され、最初はnull割り当てられnull

    public static void changeReference(Foo a)
    

  3. changeReferenceメソッドを呼び出すと、引数aとして渡されたオブジェクトに参照aが割り当てられます。

    changeReference(f);
    

  4. Foo型のbという名前の参照を宣言し、それを属性"b"持つFoo型の新しいオブジェクトに割り当てます。

    Foo b = new Foo("b");
    

  5. a = bは、その属性が"b"あるオブジェクトに参照a NOT fを再割り当てします。

  6. modifyReference(Foo c)メソッドを呼び出すと、参照cが作成され、属性"f"持つオブジェクトに割り当てられます。

  7. c.setAttribute("c"); 参照c指すオブジェクトの属性を変更し、参照f指すオブジェクトと同じオブジェクトを変更します。

私はあなたが今Javaで引数としてオブジェクトを渡す方法を理解してくれることを願っています:)


Javaは参照によって値を渡します。

したがって、渡される参照を変更することはできません。


Javaは常に値渡しです 。 残念ながら、彼らはオブジェクトの場所を「参照」と呼ぶことにしました。 オブジェクトの値を渡すと、そのオブジェクトへの参照が渡されます。 これは初心者には紛らわしいものです。

こんなふうになります:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    // we pass the object to foo
    foo(aDog);
    // aDog variable is still pointing to the "Max" dog when foo(...) returns
    aDog.getName().equals("Max"); // true
    aDog.getName().equals("Fifi"); // false 
}

public static void foo(Dog d) {
    d.getName().equals("Max"); // true
    // change d inside of foo() to point to a new Dog instance "Fifi"
    d = new Dog("Fifi");
    d.getName().equals("Fifi"); // true
}

上の例では、 aDog.getName()"Max"返します。 aDog内の値aDogは、オブジェクト参照が値渡しされるときに、関数fooDog "Fifi"と変更されません。 参照渡しだった場合、 aDog.getName()fooの呼び出しの後に"Fifi"を返します。

同様に:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    foo(aDog);
    // when foo(...) returns, the name of the dog has been changed to "Fifi"
    aDog.getName().equals("Fifi"); // true
}

public static void foo(Dog d) {
    d.getName().equals("Max"); // true
    // this changes the name of d to be "Fifi"
    d.setName("Fifi");
}

上記の例では、オブジェクトの名前がfoo(...)内部に設定されていたため、 Fififoo(aDog)呼び出し後のdogの名前foo(...)foodに対して実行する操作は、すべての実際的な目的のためにaDog自体で実行されるようなものです( d = new Dog("Boxer")などの別のDogインスタンスを指すように変更された場合を除く)。


「パス・バイ・リファレンスとパス・バイ・バリュー」は、非常に有用ではないと主張するような気がする。

「Javaはパス・バイ・ホワイテット(参照/値)」と言っても、どちらの場合でも完全な答えは得られません。 メモリ内で何が起こっているのかを理解するのに役立つ情報があります。

Javaの実装に入る前に、スタック/ヒープのコースをクラッシュする:値は、カフェテリアのプレートのスタックのように、整然としたやり方でスタック内を行き来します。 ヒープ内のメモリ(ダイナミックメモリとも呼ばれます)は不安定で混乱しています。 JVMはできるだけスペースを見つけ、それを使用する変数がもはや必要でなくなると解放します。

はい。 最初に、ローカルプリミティブがスタックに移動します。 したがって、このコード:

int x = 3;
float y = 101.1f;
boolean amIAwesome = true;

結果は次のとおりです。

オブジェクトを宣言してインスタンス化するとき。 実際のオブジェクトはヒープになります。 スタックには何がありますか? ヒープ上のオブジェクトのアドレス。 C ++のプログラマはこれをポインタと呼んでいますが、Javaの開発者の中には "ポインタ"という言葉に反するものがあります。 なんでも。 オブジェクトのアドレスがスタック上にあることを知っているだけです。

そのようです:

int problems = 99;
String name = "Jay-Z";

配列はオブジェクトなので、ヒープ上にも配置されます。 そして配列内のオブジェクトはどうですか? 彼らは自身のヒープスペースを取得し、各オブジェクトのアドレスは配列内に入ります。

JButton[] marxBros = new JButton[3];
marxBros[0] = new JButton("Groucho");
marxBros[1] = new JButton("Zeppo");
marxBros[2] = new JButton("Harpo");

では、メソッドを呼び出すと何が渡されますか? オブジェクトを渡す場合、実際に渡すのはオブジェクトのアドレスです。 アドレスの「価値」を言い表す人もいれば、オブジェクトへの参照にすぎない人もいます。 これは、 "参照"と "価値"の支持者の間の聖戦の起源です。 あなたが呼ぶものは、渡されるものがオブジェクトへのアドレスであることを理解するほど重要ではありません。

private static void shout(String name){
    System.out.println("There goes " + name + "!");
}

public static void main(String[] args){
    String hisName = "John J. Jingleheimerschmitz";
    String myName = hisName;
    shout(myName);
}

1つの文字列が作成され、そのスペースがヒープに割り当てられ、文字列へのアドレスがスタックに格納され、識別子hisName与えられます。これは、2番目のStringのアドレスが最初のStringと同じであるため、新しいヒープスペースは割り当てられませんが、新しい識別子がスタックに作成されます。 次に、 shout()を呼び出します。新しいスタックフレームが作成され、新しい識別子nameが作成され、既存のStringのアドレスが割り当てられます。

だから、価値、参考? あなたは「ポテト」と言う。


Javaでは、参照のみが渡され、値渡しされます。

Javaの引数はすべて値によって渡されます(参照はメソッドによって使用されるときにコピーされます)。

プリミティブ型の場合、Javaの振舞いは単純です。値はプリミティブ型の別のインスタンスにコピーされます。

Objectの場合、これは同じです。オブジェクト変数は、 "new"キーワードを使用して作成されたオブジェクトのアドレスのみを保持するポインタ(バケット)であり、プリミティブ型のようにコピーされます。

コピーされたオブジェクト変数に同じアドレスが含まれているため(同じオブジェクトへの)オブジェクトのコンテンツ/メンバーがメソッド内で変更され、後で外部にアクセスして、オブジェクトを含むという錯覚を与えている可能性がありますそれ自体は参照によって渡されました。

"文字列"オブジェクトは、 "オブジェクトは参照によって渡される"という都市の伝説の完全な反例であるように見えます。

実際には、あるメソッド内では、引数として渡されたStringの値を更新することはできません。

Stringオブジェクトは、最終的に宣言された配列によって文字を保持しますが、変更することはできません。オブジェクトのアドレスだけが "new"を使用して別のものに置き換えられる可能性があります。"new"を使用して変数を更新すると、変数は最初に値渡しされコピーされたため、外部からオブジェクトにアクセスすることはできません。


これは、Javaが実際にどのように機能しているのか、いくつかの洞察を与えるでしょう。

第1ステップは、あなたが他のプログラミング言語から来た場合、特に「p」「_ _ _ _ _ _ _」で始まる単語をあなたの心から抹消してください。 Javaと 'p'は同じ本、フォーラム、またはtxtで記述することはできません。

ステップ2は、メソッドにObjectを渡すときにObject参照を渡し、Object自体を渡していないことを覚えておいてください。

  • Student :Master、これはJavaが参照渡しであることを意味しますか?
  • マスター :グラスホッパー、いいえ

オブジェクトの参照/変数が何をするかを考えてみましょう:

  1. 変数は、メモリ内の参照オブジェクト(ヒープ)に到達する方法をJVMに指示するビットを保持します。
  2. 引数をメソッドに渡すときは、参照変数を渡すのではなく、参照変数のビットのコピーを渡します 。 このようなもの:3bad086a。 3bad086aは、渡されたオブジェクトに到達する方法を表します。
  3. だからあなたはちょうどそれが参照の値であることを3bad086aに渡しています。
  4. 参照の値を渡していて、参照自体ではなく(オブジェクトではなく)参照を渡しています。
  5. この値は実際にCOPIEDされ、メソッドに渡されます。

以下のようにしてください(コンパイル/実行しないでください):

1. Person person;
2. person = new Person("Tom");
3. changeName(person);
4.
5. //I didn't use Person person below as an argument to be nice
6. static void changeName(Person anotherReferenceToTheSamePersonObject) {
7.     anotherReferenceToTheSamePersonObject.setName("Jerry");
8. }

何が起こるのですか?

  • 変数personは行番号1で作成され、最初はnullです。
  • 新しいPersonオブジェクトが行#2に作成され、メモリに格納され、変数personにはPersonオブジェクトへの参照が与えられます。 つまり、そのアドレスです。 3bad086aとしましょう。
  • オブジェクトのアドレスを保持する変数personは、行番号3の関数に渡されます。
  • 4行目では、無音の音を聞くことができます
  • 5行目のコメントを確認する
  • メソッドのローカル変数 - anotherReferenceToTheSamePersonObject - が作成され、その後、行番号6の魔法になります:
    • 変数/参照は、ビットごとにコピーされ、関数内のanotherReferenceToTheSamePersonObjectに渡されます。
    • Personの新しいインスタンスは作成されません。
    • " person "と " anotherReferenceToTheSamePersonObject "は同じ値の3bad086aを保持します。
    • これを試してはいけませんが、person == anotherReferenceToTheSamePersonObjectがtrueになります。
    • どちらの変数も参照の同一コピーを持ち、同じオブジェクト、ヒープ上のSAMEオブジェクト、およびコピーではありません。

絵は千の言葉に値する:

anotherReferenceToTheSamePersonObject矢印は、オブジェクトに向けられ、可変の人に向けられていないことに注意してください。

あなたがそれを取得していない場合は、私だけを信頼し、 Javaが価値渡しであると言うことを忘れないでください。 さて、 参考値渡してください 。 まあ、変わった価値を渡すことは、 パスバイ・バイ・ザ・バリューです! ;)

今、私を嫌っても構いませんが、これを考慮すると、メソッドの引数について話すとき、プリミティブ型とオブジェクトを渡すことに違いはありません

あなたは常に参照の値のビットのコピーを渡します!

  • 基本データ型の場合、これらのビットには基本データ型自体の値が格納されます。
  • オブジェクトの場合、ビットには、JVMにオブジェクトへの到達方法を知らせるアドレスの値が格納されます。

Javaはメソッド内で参照されたオブジェクトを必要なだけ変更できるので、Javaは値渡しとなりますが、試しても何の問題もなく、渡された変数を変更することはできません(p _ _ _ _ _ _ _)何があっても同じオブジェクト!

上記のchangeName関数は、渡された参照の実際の内容(ビット値)を決して変更できません。 言い換えれば、changeNameはPerson personに別のObjectを参照させることはできません。

もちろん、あなたはそれを短くして、 Javaがパスバイバリューだと言うだけです!


Javaは価値のある呼び出しです。

使い方

  • あなたは常に参照の値のビットのコピーを渡します!

  • 基本データ型の場合、これらのビットには基本データ型自体の値が含まれています。そのため、メソッド内のheaderの値を変更すると、変更が外部に反映されません。

  • それはのようなオブジェクト・データ型だ場合)はFoo fooという=新しいFooの(この場合はオブジェクトのアドレスのコピーは、ファイルのショートカットのように渡し、その後、我々はテキストファイルがあるとしabc.txtをC:デスクトップ\と我々はのショートカットを作ると仮定同じファイルと、この内側に置くC:\デスクトップ\ abcの-ショートカットをあなたからファイルにアクセスするときにC:\デスクトップ\のabc.txtと書き込み「スタックオーバーフロー」をして、ファイルを閉じて、もう一度、あなたはショートカットからファイルを開きます書き込み'は、プログラマーが最大のオンラインコミュニティであることを覚えていれ合計ファイルの変更は」はプログラマーにとって最大のオンラインコミュニティです。我々が同じファイルにアクセスしていたたびに、ここで我々が想定することができ、ファイルを開くところから問題ではありません意味はFooをに格納されたファイルと仮定するFOOとして123hd7h(のような元のアドレスC:デスクトップの\ abc.txt \)アドレスと234jdidC:\ desktop \ abc-shortcutのようなコピーされたアドレスの中に実際にファイルの元のアドレスが入っています)..だから、より良い理解のためにショートカットファイルと感じる...


いくつかの投稿への修正。

Cは参照渡しをサポートしていません。常に値渡しです。C ++は参照渡しをサポートしていますが、デフォルトではなく非常に危険です。

Javaの値が何であるかは関係ありません。オブジェクトのプリミティブまたはアドレス(大まかに)ですが、常に値によって渡されます。

Javaオブジェクトが参照渡しのように「振る舞う」場合、それは可変性のプロパティであり、メカニズムを渡すこととはまったく関係ありません。

私はこれがなぜとても混乱しているのか分かりません。なぜなら、多くのJava "プログラマ"が正式に訓練されておらず、実際に何がメモリ上で起こっているのか分からないからでしょうか?


コントラストを表示するには、次のC++およびJavaスニペットを比較してください。

C ++: 注意:コードが不正です - メモリリーク! しかしそれはその点を実証している。

void cppMethod(int val, int &ref, Dog obj, Dog &objRef, Dog *objPtr, Dog *&objPtrRef)
{
    val = 7; // Modifies the copy
    ref = 7; // Modifies the original variable
    obj.SetName("obj"); // Modifies the copy of Dog passed
    objRef.SetName("objRef"); // Modifies the original Dog passed
    objPtr->SetName("objPtr"); // Modifies the original Dog pointed to 
                               // by the copy of the pointer passed.
    objPtr = new Dog("newObjPtr");  // Modifies the copy of the pointer, 
                                   // leaving the original object alone.
    objPtrRef->SetName("objRefPtr"); // Modifies the original Dog pointed to 
                                    // by the original pointer passed. 
    objPtrRef = new Dog("newObjPtrRef"); // Modifies the original pointer passed
}

int main()
{
    int a = 0;
    int b = 0;
    Dog d0 = Dog("d0");
    Dog d1 = Dog("d1");
    Dog *d2 = new Dog("d2");
    Dog *d3 = new Dog("d3");
    cppMethod(a, b, d0, d1, d2, d3);
    // a is still set to 0
    // b is now set to 7
    // d0 still have name "d0"
    // d1 now has name "objRef"
    // d2 now has name "objPtr"
    // d3 now has name "newObjPtrRef"
}

Javaでは、

public static void javaMethod(int val, Dog objPtr)
{
   val = 7; // Modifies the copy
   objPtr.SetName("objPtr") // Modifies the original Dog pointed to 
                            // by the copy of the pointer passed.
   objPtr = new Dog("newObjPtr");  // Modifies the copy of the pointer, 
                                  // leaving the original object alone.
}

public static void main()
{
    int a = 0;
    Dog d0 = new Dog("d0");
    javaMethod(a, d0);
    // a is still set to 0
    // d0 now has name "objPtr"
}

Javaには、組み込み型の値とオブジェクト型のポインタの値の2種類の渡しがあります。


基本的には、オブジェクトパラメータを再割り当てしても引数には影響しません(例:

private void foo(Object bar) {
    bar = null;
}

public static void main(String[] args) {
    String baz = "Hah!";
    foo(baz);
    System.out.println(baz);
}

"Hah!"が印刷され"Hah!" null代わりに。 この理由は、 barbazの値のコピーであり、これはちょうど"Hah!"への参照"Hah!" 。 それが実際の参照そのものだった場合、 foobaznull再定義しました。


私はちょうど私の記事を参照し気づいた。

Java仕様では、Javaのすべてが値渡しとなっています。 Javaでは「参照渡し」というようなことはありません。

これを理解するための鍵は、

Dog myDog;

犬ではありません 。 実際にはDogへのポインタです。

それが意味することは、あなたが持っているときです

Dog myDog = new Dog("Rover");
foo(myDog);

基本的には作成されたDogオブジェクトのアドレスfooメソッドに渡しています

(私は本質的に、Javaポインタは直接アドレスではないので、それらを考えるのは最も簡単です)

Dogオブジェクトがメモリアドレス42にあるとします。これはメソッドに42を渡すことを意味します。

メソッドが次のように定義されている場合

public void foo(Dog someDog) {
    someDog.setName("Max");     // AAA
    someDog = new Dog("Fifi");  // BBB
    someDog.setName("Rowlf");   // CCC
}

何が起きているのか見てみましょう。

  • パラメータsomeDogは値42に設定されます
  • ライン「AAA」
    • someDogは、それが指しているDogに続きます(アドレス42のDogオブジェクト)
    • そのDog (42番地のDog )は彼の名前をMaxに変更するよう頼まれています
  • ライン「BBB」
    • 新しいDogが作成されます。 彼が74番地にいるとしよう
    • パラメータsomeDogを74に代入します
  • ライン "CCC"
    • someDogはそれが指し示すDog (アドレス74のDogオブジェクト)に続き、
    • そのDog (住所74にあるDog )は彼の名前をRowlfに変更するように求められます
  • その後、私たちは戻る

さて、メソッドの外側で何が起こるか考えてみましょう。

myDog変更されましたか?

キーがあります。

myDogポインタであり、実際のDogではなく、答えはNOであることをmyDogておいてmyDogmyDogの値はまだ42です。 それはまだ元のDog指しています(ただし、 "AAA"という行のため、その名前は "Max"です - まだ同じDog; myDogの値は変更されていません)。

それ 、アドレスに従って 、それの終わりにあるものを変更することは完全に有効です。 変数を変更することはありません。

JavaはCとまったく同じように動作します。ポインタを割り当てたり、メソッドにポインタを渡したり、メソッドのポインタをたどったり、指し示されたデータを変更することができます。 ただし、ポインタがどこを指しているかは変更できません。

参照渡しをサポートするC ++、Ada、Pascalおよびその他の言語では、渡された変数を実際に変更することができます。

Javaが参照渡しのセマンティクスを持っていた場合、上で定義したfooメソッドは、 myDogがBBB行のsomeDogを割り当てたときに、 myDogが指していたところで変更されていmyDogた。

参照パラメータは、渡される変数のエイリアスと考えることができます。そのエイリアスが割り当てられると、渡された変数も割り当てられます。


4つの例の助けを借りて私の理解を説明しようとしましょう。Javaは値渡しであり、参照渡しではありません

/ **

値渡し

Javaでは、すべてのパラメータが値渡しされます。つまり、メソッド引数を代入することは呼び出し側には表示されません。

* /

例1:

public class PassByValueString {
    public static void main(String[] args) {
        new PassByValueString().caller();
    }

    public void caller() {
        String value = "Nikhil";
        boolean valueflag = false;
        String output = method(value, valueflag);
        /*
         * 'output' is insignificant in this example. we are more interested in
         * 'value' and 'valueflag'
         */
        System.out.println("output : " + output);
        System.out.println("value : " + value);
        System.out.println("valueflag : " + valueflag);

    }

    public String method(String value, boolean valueflag) {
        value = "Anand";
        valueflag = true;
        return "output";
    }
}

結果

output : output
value : Nikhil
valueflag : false

例2:

/ ** * *渡す値* * /

public class PassByValueNewString {
    public static void main(String[] args) {
        new PassByValueNewString().caller();
    }

    public void caller() {
        String value = new String("Nikhil");
        boolean valueflag = false;
        String output = method(value, valueflag);
        /*
         * 'output' is insignificant in this example. we are more interested in
         * 'value' and 'valueflag'
         */
        System.out.println("output : " + output);
        System.out.println("value : " + value);
        System.out.println("valueflag : " + valueflag);

    }

    public String method(String value, boolean valueflag) {
        value = "Anand";
        valueflag = true;
        return "output";
    }
}

結果

output : output
value : Nikhil
valueflag : false

例3:

/ **この「パスバイバリュー」は「参照渡し」の感情を持っています

一部の人々はプリミティブ型と '文字列'は '値渡し'であり、オブジェクトは '参照渡し'としています。

しかし、この例からは、値が渡されていることを念頭に置いて、実際に値渡しであることがわかります。すなわち、参照は値渡しされます。そのため、変更が可能であり、引き続き現地のスコープの後に適用されます。しかし、元の範囲外の実際の参照を変更することはできません。つまり、PassByValueObjectCase2の次の例で示すことができます。

* /

public class PassByValueObjectCase1 {

    private class Student {
        int id;
        String name;
        public Student() {
        }
        public Student(int id, String name) {
            super();
            this.id = id;
            this.name = name;
        }
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return "Student [id=" + id + ", name=" + name + "]";
        }
    }

    public static void main(String[] args) {
        new PassByValueObjectCase1().caller();
    }

    public void caller() {
        Student student = new Student(10, "Nikhil");
        String output = method(student);
        /*
         * 'output' is insignificant in this example. we are more interested in
         * 'student'
         */
        System.out.println("output : " + output);
        System.out.println("student : " + student);
    }

    public String method(Student student) {
        student.setName("Anand");
        return "output";
    }
}

結果

output : output
student : Student [id=10, name=Anand]

例4:

/ **

Example3(PassByValueObjectCase1.java)で述べたことに加えて、元のスコープ外の実際の参照を変更することはできません。

注:私はコードを貼り付けませんprivate class Student。のクラス定義StudentはExample3と同じです。

* /

public class PassByValueObjectCase2 {

    public static void main(String[] args) {
        new PassByValueObjectCase2().caller();
    }

    public void caller() {
        // student has the actual reference to a Student object created
        // can we change this actual reference outside the local scope? Let's see
        Student student = new Student(10, "Nikhil");
        String output = method(student);
        /*
         * 'output' is insignificant in this example. we are more interested in
         * 'student'
         */
        System.out.println("output : " + output);
        System.out.println("student : " + student); // Will it print Nikhil or Anand?
    }

    public String method(Student student) {
        student = new Student(20, "Anand");
        return "output";
    }

}

結果

output : output
student : Student [id=10, name=Nikhil]

Javaではすべてが参考になるので、Point pnt1 = new Point(0,0);Javaの場合は次のようになります。

  1. 新しいPointオブジェクトを作成します。
  2. 新しいPoint参照を作成し、その参照を初期化して、以前に作成したPointオブジェクトをポイントする(参照する)
  3. ここから、Pointオブジェクトのライフサイクルを通して、pnt1リファレンスを通してそのオブジェクトにアクセスします。だから、Javaでは、参照によってオブジェクトを操作すると言うことができます。

Javaはメソッド引数を参照渡ししません。それは価値によってそれらを渡します。このサイトの例を使用します

public static void tricky(Point arg1, Point arg2) {
  arg1.x = 100;
  arg1.y = 100;
  Point temp = arg1;
  arg1 = arg2;
  arg2 = temp;
}
public static void main(String [] args) {
  Point pnt1 = new Point(0,0);
  Point pnt2 = new Point(0,0);
  System.out.println("X1: " + pnt1.x + " Y1: " +pnt1.y); 
  System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y);
  System.out.println(" ");
  tricky(pnt1,pnt2);
  System.out.println("X1: " + pnt1.x + " Y1:" + pnt1.y); 
  System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y);  
}

プログラムの流れ:

Point pnt1 = new Point(0,0);
Point pnt2 = new Point(0,0);

異なる2つの参照が関連付けられた2つの異なるPointオブジェクトを作成する。

System.out.println("X1: " + pnt1.x + " Y1: " +pnt1.y); 
System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y);
System.out.println(" ");

期待される出力は次のようになります。

X1: 0     Y1: 0
X2: 0     Y2: 0

このラインでは、「値渡し」がプレイに入ります...

tricky(pnt1,pnt2);           public void tricky(Point arg1, Point arg2);

参考資料pnt1とはpnt2されている値によって渡された今、あなたの参照ことを意味し、トリッキーな方法にpnt1しては、pnt2自分の持っているcopiesという名前arg1arg2。だからpnt1arg1 ポイントを同じオブジェクトに。(同じもののためpnt2arg2

このtricky方法では:

 arg1.x = 100;
 arg1.y = 100;

次のtricky方法

Point temp = arg1;
arg1 = arg2;
arg2 = temp;

ここでは、まずtemp参照のような同じ場所を指す新しいPoint参照を作成しarg1ます。その後、参照を移動arg1するために指すように同じ場所にarg2言及。最後に、同じ場所arg2指しtempます。

ここからの範囲tricky方法がなくなって、あなたは、それ以上の言及にはアクセスできません:arg1arg2tempしかし、重要な点は、「人生の中で」これらの参照を使用して行うすべてが、それらが指し示すオブジェクトに永続的に影響することです。

だから、メソッドを実行した後にtricky戻るとmain、次のような状況になります。

今、プログラムの完全な実行は:

X1: 0         Y1: 0
X2: 0         Y2: 0
X1: 100       Y1: 100
X2: 0         Y2: 0

JavaはVALUEによってパラメータを渡し、その値によってONLY

ショートストーリーを短縮するには:

C#から来た人には:"out"パラメータはありません。

パスカルからのもの:"var"パラメータはありません。

つまり、オブジェクト自体から参照を変更することはできませんが、オブジェクトのプロパティはいつでも変更できます。

回避策は、StringBuilder代わりにパラメータを使用する方法ですString。そして、あなたはいつも配列を使うことができます!


Javaは価値のあるものだけを渡しています。これを検証する簡単な例です。

public void test() {
    MyClass obj = null;
    init(obj);
    //After calling init method, obj still points to null
    //this is because obj is passed as value and not as reference.
}
private void init(MyClass objVar) {
    objVar = new MyClass();
}

問題の核心は、ワードということである参照表現では「参照渡し」単語の通常の意味とは完全に異なる何かを意味リファレンス Javaでを。

通常Java リファレンスで、オブジェクトへの参照を意味します。しかし、プログラミング言語理論からの参照/値によって渡される技術用語は、変数を保持するメモリセルへの参照であり、これはまったく異なるものです。


私が以前のポスターと同じ印象を受けていたのと同じように、覚えておいても差し支えないのは、Javaは常に価値があるということです。Javaのすべてのオブジェクト(Javaでは、プリミティブ以外のもの)は参照です。これらの参照は値渡しされます。


私はhereどのようなプログラミング言語hereこの種の質問に捧げられたスレッドを作りました。

Javaも言及されている。短いサマリーはここにあります:

  • Javaはそれを値によってパラメータに渡します
  • メソッドによってパラメータを渡す唯一の方法は "by value"です
  • パラメータとして与えられたオブジェクトのメソッドを使用すると、参照が元のオブジェクトを指すようにオブジェクトが変更されます。(そのメソッド自体がいくつかの値を変更する場合)

私はいつもそれを「コピーで渡す」と考えています。これは、原始的であるか基準であるかの価値のコピーです。それがプリミティブであれば、それは値であるビットのコピーであり、それがオブジェクトであれば、それは参照のコピーである。

public class PassByCopy{
    public static void changeName(Dog d){
        d.name = "Fido";
    }
    public static void main(String[] args){
        Dog d = new Dog("Maxx");
        System.out.println("name= "+ d.name);
        changeName(d);
        System.out.println("name= "+ d.name);
    }
}
class Dog{
    public String name;
    public Dog(String s){
        this.name = s;
    }
}

java PassByCopyの出力:

name = Maxx
name = Fido

プリミティブラッパークラスとストリングは不変ですので、これらの型を使用する例は他の型/オブジェクトと同じように動作しません。





pass-by-value