初心者Java質問ですが、以下の例で値渡し(またはReference)がどのように機能するか理解できません-
カスタム文字列オブジェクトの場合、メソッドを終了した後、文字列値が変更されないのはなぜですか。 ? Dateなどの他のクラスと同じです。
public class StringMadness {
public static void main(String[] args) {
String s = "Native String";
CustomStringObject cs = new CustomStringObject();
System.out.println("Custom String Before: " + cs.str);
hello(cs);
System.out.println("Custom String After: " + cs.str);
System.out.println("Native String Before: " + s);
hello(s);
System.out.println("Native String After: " + s);
}
private static void hello(String t) {
t = "hello " + t;
}
private static void hello(CustomStringObject o) {
o.str = "hello " + o.str;
}
}
class CustomStringObject {
String str = "Custom String";
}
次の2つの方法を比較してください。
private static void hello(String t) {
t = "hello " + t;
}
private static void hello(CustomStringObject o) {
o.str = "hello " + o.str;
}
最初のケースでは、t
に新しい値を割り当てています。これは呼び出し元のコードには影響を与えません。パラメーターの値を変更するだけで、すべての引数はJavaの値によって渡されます。
2番目のケースでは、o.str
に新しい値を割り当てています。それはフィールドの値を変更していますオブジェクト内o
の値が参照するものです。呼び出し元willが変更を確認します。これは、呼び出し元がまだそのオブジェクトへの参照を持っているためです。
つまり、Javaは常に値渡しを使用しますが、クラスの場合、変数(または実際には他の式)の値はオブジェクトではなく参照であることを覚えておく必要があります。これを確認するためにパラメーターを渡す必要はありません。
Foo foo1 = new Foo();
Foo foo2 = foo1;
foo1.someField = "changed";
System.out.println(foo2.someField) // "changed"
ここの2行目は、foo1
の値をfoo2
にコピーします。2つの変数は同じオブジェクトを参照しているため、どの変数を使用してアクセスしてもかまいません。
2つの方法には重要な違いがあります。hello(String)
を使用すると、referenceをString
に変更しようとしていますが、hello(CustomObject)
参照を指定すると、参照を使用してオブジェクトのメンバーを変更します。
hello(String)
はString
への参照を受け取ります。関数では、参照先のオブジェクトを変更しようとしていますが、参照の値渡しのみを変更しています。そのため、変更はメソッドの外部には反映されません。
hello(CustomObject)
には、オブジェクトへの参照のコピーが与えられます。これを使用して、実際のオブジェクトを変更できます。これを、オブジェクトのcontentsを変更すると考えてください。したがって、変更あるが呼び出し元に反映されます。
参照をオブジェクトに指定すると、公開されたメソッド/フィールドを使用してオブジェクトを変更できます
t
は新しいオブジェクトをポイントし、メソッドのみをスコープとするため、変更は外部からは見えません。
2番目のケースでは、変更する値はオブジェクトに更新されるため、これらの変更はメソッド呼び出しの後に表示されます。
Stringは不変オブジェクトであるため機能しません
文字列の場合、ローカルパラメータ参照を変更しているだけだからです。