web-dev-qa-db-ja.com

なぜこれがNullPointerExceptionをスローしないのですか?

次のコードの説明:

StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
referToSample.append("B");
System.out.println(sample);

これによりBが出力され、sampleおよびreferToSampleオブジェクトが同じメモリ参照を参照していることが証明されます。

StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
sample.append("A");
referToSample.append("B");
System.out.println(referToSample);

これは、同じことを証明するABを出力します。

StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
referToSample = null;
referToSample.append("A");
System.out.println(sample);

明らかに、これはNullPointerExceptionをスローします。これは、null参照でappendを呼び出そうとしているためです。

StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
referToSample = null;
sample.append("A");
System.out.println(sample);

だから私の質問です、最後のコードサンプルがNullPointerExceptionをスローしないのはなぜですか。その他は、両方が同じメモリ参照を指しているためです。では、なぜそのルールがここに適用されないのですか? nullをreferToSampleに割り当てると、サンプルもnullになり、NullPointerExceptionがスローされますが、スローされません。なぜですか?

89
commit

null割り当ては、そのオブジェクトをグローバルに破棄してもvalueは変更されません。このような動作は、追跡が困難なバグや直感に反する動作につながります。それらはその特定の参照のみを破壊します。

簡単にするために、sampleがアドレス12345を指しているとしましょう。これはおそらくアドレスではなく、ここでは物事を簡単にするためにのみ使用されています。 アドレスはtypicalであり、Object#hashCode()で指定された奇妙な16進数で表されますが、これは実装に依存します。1

StringBuilder sample = new StringBuilder(); //sample refers to 
//StringBuilder at 12345 

StringBuilder referToSample = sample; //referToSample refers to 
//the same StringBuilder at 12345 
//SEE DIAGRAM 1

referToSample = null; //referToSample NOW refers to 00000, 
//so accessing it will throw a NPE. 
//The other reference is not affected.
//SEE DIAGRAM 2

sample.append("A"); //sample STILL refers to the same StringBuilder at 12345 
System.out.println(sample);

See diagramとマークされた行から、そのときのオブジェクトの図は次のとおりです。

図1:

[StringBuilder sample]    -----------------> [Java.lang.StringBuilder@00012345]
                                                      ↑
[StringBuilder referToSample] ------------------------/

図2:

[StringBuilder sample]    -----------------> [Java.lang.StringBuilder@00012345]

[StringBuilder referToSample] ---->> [null pointer]

図2は、referToSampleを無効にしても、00012345にあるStringBuilderへのsampleの参照が壊れないことを示しています。

1GCの考慮事項により、これは現実的ではありません。

最初はreferToSampleが以下に示すようにsampleを参照していたとおっしゃったとおりです。

1。シナリオ1:

referToSample refers to sample

2。シナリオ1(続き):

referToSample.append("B")

  • ここでreferToSamplesampleを参照していたため、書き込み中に「B」を追加しました

    referToSample.append("B")

同じことがScenario2:でも起こりました

しかし、3。Scenario3:では、6分数が言ったように、

nullreferToSampleに割り当てたとき、それがsampleを参照していたとき、変更されませんでしたvalue代わりにreferenceが壊れます= sampleから、現在はnowhereを指しています。以下に示すように:

when referToSample = null

さて、referToSamplenowhereを指すので、referToSample.append("A");の間、値や参照はありません。 Aを追加できます。つまり、NullPointerExceptionをスローします。

BUT sampleは、初期化したときと同じです。

StringBuilder sample = new StringBuilder();なので初期化されているため、Aを追加でき、NullPointerExceptionをスローしません

62
Parth

簡単に言えば、オブジェクトではなく参照変数にnullを割り当てます。

1つの例では、2つの参照変数によって参照されるオブジェクトのstateを変更します。これが発生すると、両方の参照変数に変更が反映されます。

別の例では、1つの変数に割り当てられた参照を変更しますが、これはオブジェクト自体には影響しないため、元のオブジェクトを参照している2番目の変数はオブジェクトの状態の変化に気づきません。


特定の「ルール」について:

2つのオブジェクトが同じオブジェクトを参照している場合、値を変更すると、両方が同じメモリ参照を指しているため、他のオブジェクトにも反映されます。

ここでも、両方の変数が参照する1つのオブジェクトのstateを変更することを参照しています。

では、なぜそのルールがここに適用されないのですか? referToSampleにnullを割り当てると、サンプルもnullになり、nullPointerExceptionがスローされますが、スローされません。なぜですか?

繰り返しますが、ある変数のreferenceを変更すると、他の変数のreferenceに対して完全にno effectになります。

これらは2つのまったく異なるアクションであり、2つのまったく異なる結果になります。

次の簡単な図を参照してください。

diagram

referToSampleメソッドを呼び出すと、[your object]が更新されるため、sampleにも影響します。しかし、あなたが言うときreferToSample = nullの場合、referToSamplerefersを単に変更するだけです。

8
Doorknob

ここで、「sample」と「referToSample」は同じオブジェクトを参照しています。これは、同じメモリロケーションにアクセスする異なるポインタの概念です。したがって、1つの参照変数をnullに割り当てても、オブジェクトは破棄されません。

   referToSample = null;

nullのみを指す「referToSample」を意味します。オブジェクトは同じままで、他の参照変数は正常に機能しています。したがって、nullを指さず、有効なオブジェクトを持つ「サンプル」の場合

   sample.append("A");

正常に動作します。しかし、「referToSample」にnullを追加しようとすると、NullPointExceptionが表示されます。あれは、

   referToSample .append("A");-------> NullPointerException

そのため、3番目のコードスニペットでNullPointerExceptionが発生しました。

3
NCA

newキーワードを使用すると、ヒープにオブジェクトが作成されます

1)StringBuilderサンプル= new StringBuilder();

2)StringBuilder referToSample = sample;

2)で、referSampleの参照が同じオブジェクトサンプルに作成されます

したがってreferToSample = null; is nulling referSample参照のみがサンプルに影響を与えないため、JavaのガベージコレクションのおかげでNULLポインタ例外が発生しません。

0
nitesh

簡単です、Java参照渡しではなく、オブジェクト参照を渡すだけです。

0
Peerapat A