레퍼런스 변수를 선언하면 객체의 포인터가 생성된다. 즉, 레퍼런스 변수는 객체의 주소(참조값)을 저장한다. Primitive 타입인 int 타입의 변수를 다음과 같이 선언해 본다고 가정하자.
int x;
x = 10;
이 예제의 첫번째 줄에서 변수 x는 int 타입으로 선언되며, 자바는 이 변수의 값을 0으로 초기화한다.(단, 변수 x가 클래스의 필드로 정의되었을 때). 그리고 두 번째 줄과 같이 해당 변수 x에 10이라는 값을 대입 연산자를 사용해 할당하면, 변수 이름 x가 가리키는 메모리 위치에 10이라는 값이 쓰여진다.
그러나 레퍼런스 타입의 변수를 선언할 때는 다르게 처리된다. 다음의 예제를 보자.
Integer num;
num = new Integer(10);
첫번째 줄에서 num이라는 이름으로 선언된 변수는 Primitive 값을 저장하지 않는다. 대신, Integer라는 이름의 타입은 래퍼클래스로서, 레퍼런스 타입이므로 해당 변수는 주소(참조값)을 저장한다. 첫번째 줄은 아직 어떤 것을 참조하라고 정의하지 않았기 때문에 자바는 그 변수를 null로 초기화한다. (단, 변수 num이 클래스의 필드로 정의되었을 때). 이것은 "나는 아무것도 참조하지 않아."라는 의미이다.
두 번째 줄은 new라는 키워드를 사용해서 Integer 클래스 객체를 생성하고 해당 객체의 주소(참조값)을 num이라는 변수에 저장한다. 이렇게 객체를 생성하고 객체를 참조값을 저장한 변수를 사용해서 해당 객체에 접근할 수 있다. 이때 . 연산자를 사용한다.
만약 레퍼런스 타입의 변수를 선언하고 객체를 생성하지 않으면(즉, 객체의 참조값을 해당 변수에 저장하지 않으면) Exception이 발생된다. 즉, 객체가 생성되기 전에 num 변수를 사용해서 해당 클래스의 객체를 접근하고자 하면 NullPointerException이 발생된다. 이러한 경우 대부분 컴파일러가 해당 문제를 인식해서 "num 변수가 아직 초기화되지 않았다"고 경로 메시지로 알려줄 것이다.
아래와 같은 메소드에 대해서,
public void doSomething(Integer num) {
// do something to num
}
다음과 같이 호출한다면,
doSomething(null);
num 변수의 값은 null이 된다. 이러한 null 값을 가지는 num 변수를 사용해서 객체의 필드 혹은 메소드에 접근하고자 한다면 NullPointerException이 발생하게 되는 것이다. 이와 같은 Exception이 발생되지 않게 하는 최선의 방법은 다음과 같이 레퍼런스 변수를 사용하기 전에 null 값을 저장하고 있는지를 체크하는 것이다.
public void doSomething(Integer num){
if(num != null) {
// do something to num
}
}
Java의 NullPointerException은 런타임 예외이다. Java는 개체 참조에 null 값을 할당한다. null 값으로 설정된 객체 참조를 사용하려고 하면 이 예외가 throw 된다.
참고