0

この Java コードがあるとしましょう (中間レビュー!):

public class A {
public int key;
}

public class B extends A {
}

public class Problem1 {
public static void f(A x) {
A y = x;
y.key = x.key + 1;
}

public static void f(B x) {
B y = new B();
y.key = x.key + 2;
x = y;
}

public static void main(String[] args) {
A p = new A();
p.key = 3;
B q = new B();
q.key = 10;
f(p);
f(q);
p = q;
f(p);
System.out.println(p.key);
}
}

p = q を正しく理解しているかどうかはわかりません。これまでの私の理解は次のとおりです。B は A を拡張するため、この操作は許可されますが、p と q が同じオブジェクトを指すようにはなりません。むしろ、p のキー値を更新しますが、クラス A のままです。これが、最後に f(p) が 11 を返す理由です。これは、以前に Java について知っていると思っていたことと一致しないため、説明をいただければ幸いです。

たとえば、int a = 4 および int b = 3 の場合、次のようにします。

a = b;
b++;
return a;

b が指しているのと同じものを指しているはずなのに、a は 3 を返しますか?

お知らせ下さい。

4

3 に答える 3

1

考えてみてください。Java プリミティブは、実際の値をメモリ バイト領域に保持します。したがって、a = 4b = 3の場合、8 バイトのマシン メモリ領域は (バイナリで) のようにそれを保持できます。

a = 0 0 0 0 0 0 1 1 
b = 0 0 0 0 0 0 1 0

今、あなたが言うときa=b;

a = 0 0 0 0 0 0 1 0 
b = 0 0 0 0 0 0 1 0

それでb++ (i.e. b = b+1)

a = 0 0 0 0 0 0 1 0 
b = 0 0 0 0 0 0 1 1

それで

return a;

Then  a = 0 0 0 0 0 0 1 0 (i.e. 3)

プリミティブな値としてご理解いただければ幸いです。ただし、Java のオブジェクトの場合、これはまったく別のケースです。

ここで、a と b はプリミティブではなく、int フィールドを持つオブジェクトだと考えてください。Sample クラスは次のようになります。

class Test {
private int value;

public Test(int value){
 this.value = value;
}

public int getValue(){
return value;
}

public int increment(){
value++;
}
}

次にa = new Test(4); and b = new Test(3);、メモリ内で次のように表されます。

ヒープ:

a = x63489DF8 ---> [Test(4) Object, value = 4, Heap Memory address = x63489DF8]
b = xDFA78945 ---> [Test(3) Object, value = 3, Heap Memory address = xDFA78945]

(aそしてb、オブジェクトを指すヒープメモリアドレスを保持します)

今、あなたが言うときa=b;

a = xDFA78945 ---> [Test(3) Object value = 3, Heap Memory address = xDFA78945]
b = xDFA78945 ---> [Test(3) Object value = 3, Heap Memory address = xDFA78945]

(メモリ アドレス内のオブジェクトx63489DF8はガベージ コレクション可能でありa, b、同じオブジェクトを参照しています)

ここで、b と言うと.increment();、メモリ領域内のオブジェクトxDFA78945が操作され、新しいオブジェクトは になり[Test(3) Object value = 4, Heap Memory address = xDFA78945]ます。

a = xDFA78945 ---> [Test(3) Object value = 4, Heap Memory address = xDFA78945]
b = xDFA78945 ---> [Test(3) Object value = 4, Heap Memory address = xDFA78945]

(どちらも実際には同じオブジェクトを指しているため、変更は両方の参照を反映していることに注意してください)

returna.getValue()は 4 を返すようになりました (つまり、参照によって行われた変更bは、参照にも反映さaれます) 。

于 2013-10-08T03:58:33.360 に答える
0

すべての変数はビット ホルダーです。わかった

したがって、プリミティブ型の場合、プリミティブのビットラベル表現を表すビットを保持します。

a = b; b++; return a;

ここでは、「3」のビット表現が「a」に割り当てられているため、現在は 3 です。しかし、b はまだ「3」を表すビットを保持しているため、b の cange は「b」だけに固執します。

a がクラス変数で b もある場合、Java 変数では常にビットが保持されます。クラス変数の場合、ヒープ上に存在するクラス オブジェクトに到達するためのパスを表すビットを保持します。したがって、これを行うa = b;と、ヒープ上にあるオブジェクトに到達するためのパスも保持されます。したがって、「a」と「b」は両方とも同じオブジェクトへのパスを保持しています。

「a」のプロパティを変更した場合(var「a」が保持するパスが到達するオブジェクトのプロパティを変更)。bに反映されます。これらは同じ変数を指しているためです。 ここに画像の説明を入力

于 2013-10-08T04:39:27.743 に答える
0

たとえば、int a = 4 および int b = 3 の場合、次のようにします。

a = b;
b++;
return a;

b が指しているのと同じものを指しているはずなのに、a は 3 を返しますか?

プリミティブは、期待どおりに処理されます。つまり、a は b の数値またはビット値を取得しているため、値 3 を返します。ただし、 autoboxingimmutabilityを調べる必要があります。

p = q を正しく理解しているかどうかはわかりません。これまでの私の理解は次のとおりです。B は A を拡張するため、この操作は許可されますが、p と q が同じオブジェクトを指すようにはなりません。むしろ、p のキー値を更新しますが、クラス A のままです。

オブジェクトに関しては、操作p = qは実際には p を q と同じオブジェクトに「参照」するように割り当てます (下部のリンクを参照)。だからこそ、防御コピーのようなアプローチが必要なのです。

これは、Javaがオーバーロードされたメソッドを介して値を渡しているにもかかわらず、変更が行われる理由も説明していfます。パラメーターxはそのまま残り、プロセスがメソッド スコープを離れるとすぐに消えますが、参照されたオブジェクトの状態は変更できます。

これは、C ポインターと Java 参照の違いに関する質問です。

https://softwareengineering.stackexchange.com/questions/141834/how-is-a-Java-reference-different-from-ac-pointer

于 2013-10-08T04:12:59.000 に答える