NullPointerException이 발생하지 않는 이유는 무엇입니까?


89

다음 코드에 대한 명확한 설명 :

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

B증명 samplereferToSample객체가 동일한 메모리 참조를 참조하도록 인쇄됩니다 .

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);

null 참조 NullPointerException를 호출하려고하기 때문에 분명히 이것은 던질 것 append입니다.

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

그래서 여기에 내 질문 NullPointerException이 있습니다. 처음 두 예제에서보고 이해하는 것은 두 개체가 동일한 개체를 참조하는 경우 값을 변경하면 두 개체가 모두를 가리키고 있기 때문에 다른 개체에도 반영되기 때문에 마지막 코드 샘플이 던지지 않는 이유는 무엇입니까? 동일한 메모리 참조. 그렇다면 그 규칙이 여기에 적용되지 않는 이유는 무엇입니까? nullreferToSample에 할당 하면 샘플도 null이어야하고 NullPointerException을 throw해야하지만 throw하지 않는 이유는 무엇입니까?


31
sample여전히 sample입니다. 당신은 단지 변경했습니다 referToSample.
Dave Newton

25
찬성 / 별표 표시됨! 아주 기본적인 질문,하지만이 문제를 설명의 아름다운 예이다 잘 질문을.
Ryan Ransford 2013 년

15
귀하의 질문에 용어에 1 점 : 당신은 참조 유지 samplereferToSample같은 객체 가 변수입니다,하지만 그들은되지는 개체입니다. 변수는 객체에 대한 참조를 보유 할 수 있지만 그 자체가 객체는 아닙니다. 미묘한 차이이지만 기본적으로 혼란의 본질입니다.
Daniel Pryden 2013-09-05

1
객체 변수를 포인터로 생각하면 도움이됩니다. 변수에 작용 상관 연산자 ( volatile, final, =, ==...) 개체 변수에 적용되는 경우의 영향 의 포인터 가 아니라 그것이 참조하는 개체.
MikeFHay 2013 년

2
@Arpit 나는 정중하게 동의하지 않습니다. 이 질문에는 큰 개념이 숨겨져 있습니다. 즉, 객체참조 의 차이입니다. 해당 객체에 입니다. 대부분의 경우 우리는이 차이를 인식 할 필요가 없으며 (원하지도 않음) 언어 디자이너는이를 숨기려고 열심히 노력합니다. 예를 들어 C ++에서 참조에 의한 전달 인수를 생각해보십시오. 그래서 초보자들이 그 모든 마법에 혼란스러워하는 것을 보는 것은 놀라운 일이 아닙니다!
Gyom

답변:


89

null할당은 해당 개체를 전체적으로 삭제하여 을 변경하지 않습니다 . 그런 종류의 행동은 추적하기 어려운 버그와 반 직관적 인 행동으로 이어질 것입니다. 그들은 단지 그 특정 참조를 깨뜨 립니다.

간단하게 sample하기 위해 주소 12345 를 가리키고 있다고 가정 해 보겠습니다. 이것은 주소가 아닐 수 있으며 여기서 일을 간단하게 만드는 데만 사용됩니다. 주소는 일반적으로에 제공된 이상한 16 진수로 표시 Object#hashCode()되지만 구현에 따라 다릅니다. 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는 무효화 referToSamplesample에서 StringBuilder에 대한 참조를 중단하지 않음을 보여줍니다 00012345.

1 GC 고려 사항으로 인해이를 믿을 수 없습니다.


@commit, 이것이 귀하의 질문에 답이된다면 위의 텍스트 왼쪽에있는 투표 화살표 아래의 체크 표시를 클릭하십시오.
Ray Britton 2013 년

@RayBritton 사람들이 가장 많이 득표 한 답변이 반드시 질문에 대한 답변이라고 가정하는 방식을 좋아합니다. 그 수는 중요하지만 이것이 유일한 지표는 아닙니다. -1 및 -2 답변은 OP를 가장 많이 도왔 기 때문에 받아 들여질 수 있습니다.
nanofarad

11
hashCode()이다 없는 메모리 주소와 같은 일이
케빈 Panko

6
ID hashCode는 일반적으로 메서드가 처음 호출 될 때 개체의 메모리 위치에서 파생됩니다. 그 이후로 해당 hashCode는 고정되고 메모리 관리자가 객체를 다른 메모리 위치로 이동하기로 결정하더라도 기억됩니다.
Holger

3
대체하는 클래스는 hashCode일반적으로 메모리 주소와 관련이없는 값을 반환하도록 정의합니다. 나는 당신이 언급하지 않고 객체 참조 대 객체에 대해 당신의 주장을 할 수 있다고 생각합니다 hashCode. 메모리 주소를 얻는 방법에 대한 세부 사항은 다른 날 동안 남겨 둘 수 있습니다.
Kevin Panko 2013 년

62

처음에는 아래에 표시된대로 referToSample언급 sample한대로 였습니다 .

1. 시나리오 1 :

referToSample은 샘플을 참조합니다.

2. 시나리오 1 (계속) :

referToSample.append ( "B")

  • 여기에서 referToSample를 참조 sample했으므로 작성하는 동안 "B"가 추가되었습니다.

    referToSample.append("B")

Scenario2 에서도 같은 일이 발생했습니다 .

그러나 3. Scenario3에서 : hexafraction이 말했듯이,

참조 할 때 할당 nullreferToSamplesample변경하지 않았습니다. 대신 참조끊고 이제 아무데도 가리 키지 않습니다 . 아래 그림과 같이:sample

referToSample = null 인 경우

이제 아무데도referToSample 점이 없으므로 A를 추가 할 수있는 값이나 참조가 없을 것입니다. 따라서 .referToSample.append("A");NullPointerException

그러나 sample초기화 한 것과 여전히 동일합니다.

StringBuilder sample = new StringBuilder(); 초기화되었으므로 이제 A를 추가 할 수 있습니다. NullPointerException


5
멋진 다이어그램. 그것을 설명하는 데 도움이됩니다.
nanofarad

좋은 다이어그램이지만 하단의 메모는 'Now referToSample이 ""를 참조하지 않습니다. 여야합니다. 왜냐하면 referToSample = sample;샘플을 참조 할 때 참조되는 주소 만 복사하기 때문입니다
Khaled.K

17

간단히 말해서, 객체가 아닌 참조 변수에 null을 할당합니다.

한 가지 예 에서 두 개의 참조 변수가 참조하는 객체 의 상태 를 변경합니다 . 이 경우 두 참조 변수 모두 변경 사항을 반영합니다.

또 다른 예에서는 하나의 변수에 할당 된 참조를 변경하지만 이것은 객체 자체에는 영향을 미치지 않으므로 원래 객체를 참조하는 두 번째 변수는 객체 상태의 변경을 인식하지 못합니다.


특정 "규칙"에 관해서 :

두 객체가 동일한 객체를 참조하는 경우 값을 변경하면 둘 다 동일한 메모리 참조를 가리 키기 때문에 다른 값도 반영됩니다.

다시 말하지만, 두 변수가 참조 하는 한 개체 의 상태 를 변경하는 것을 참조합니다.

그렇다면 그 규칙이 여기에 적용되지 않는 이유는 무엇입니까? referToSample에 null을 할당하면 sample도 null이어야하며 nullPointerException을 throw해야하지만 throw되지 않는 이유는 무엇입니까?

다시 말하지만, 다른 변수 의 참조전혀 영향주지 않는 한 변수 의 참조 를 변경합니다 .

이것은 완전히 다른 두 가지 작업이며 두 가지 완전히 다른 결과를 초래합니다.


3
@commit : 모든 Java의 기초가되는 기본적이지만 중요한 개념이며, 한 번 보면 절대 잊지 못할 것입니다.
장어로 가득한 호버크라프트

8

이 간단한 다이어그램을 참조하십시오.

도표

당신이 호출 할 때 방법referToSample, 다음 [your object]이 영향을 미치는, 그래서 업데이트됩니다 sample너무. 당신이 말할 때 referToSample = null, 당신은 단순히 무엇을 변경하고 referToSample 의미 합니다.


3

여기서 'sample'과 'referToSample'은 동일한 객체를 참조하는 것으로 동일한 메모리 위치에 액세스하는 다른 포인터의 개념입니다. 따라서 하나의 참조 변수를 null에 할당해도 객체가 파괴되지 않습니다.

   referToSample = null;

의미 'referToSample'은 null 만 가리키고 객체는 동일하게 유지되며 다른 참조 변수는 정상적으로 작동합니다. 따라서 null을 가리 키지 않고 유효한 객체를 갖는 'sample'의 경우

   sample.append("A");

잘 작동합니다. 그러나 'referToSample'에 null을 추가하려고하면 NullPointException이 표시됩니다. 그건,

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

이것이 세 번째 코드 조각에서 NullPointerException이 발생한 이유입니다.


0

키워드가 사용될 때마다 힙에 객체를 생성합니다.

1) StringBuilder 샘플 = new StringBuilder ();

2) StringBuilder referToSample = 샘플;

2) referSample의 참조가 동일한 객체 샘플에 생성됩니다.

따라서 referToSample = null; 샘플에 영향을 미치지 않는 referSample Reference 만 Nulling이므로 Java의 Garbage Collection 덕분에 NULL 포인터 예외가 발생하지 않습니다.


0

간단합니다. Java는 참조로 전달하지 않고 객체 참조 만 전달합니다.


2
매개 변수 전달 의미론은 설명 된 상황과 실제로 관련이 없습니다.
Michael Myers
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.