[Java]객체와 메모리의 관계, null과 NullPointerException의 정리 및 예제
이번 포스팅에서는 메모리에 생성된 객체와 레퍼런스의 관계에 대해 살펴보고
null이 무엇인지에 관해서 다뤄보고자 한다.
1. 메모리에서 객체 생성과 제거
모든 객체는 프로그램이 동작하는 중에 new키워드로 동적으로 생성되게 된다.
우리가 예를 들어 다음과 같이 코드를 짰다고 해보자
public class Item{
private String name;
private int price;
}
public class main{
public static void main(String[] args){
Item item=new Item();
}
}
메인에서 item이라는 변수 안에 New키워드로 객체를 생성해준 코드이다.
이 때 주의해야 할 점은 item이라는 변수 안에는
Item객체의 크기 만큼의 메모리가 할당되어 객체값이 들어가는 것이 아니라
Item객체는 자바 메모리중 힙(Heap)공간에 생성되고
item변수 안에는 힙 공간에 생성된 곳의 메모리 주소가 담기는 것이다.
(신입 프로그래머 분들과 이야기해보면 이 내용을 모르는 분들이 은근히 많다)
그리고 저 item이라는 변수에 담긴 주소값이 사라지면(=null이 담기면)
힙 공간에 생성되었던 Item객체는 가비지컬렉터(GC)에 의해 제거된다.
그림으로 나타내면 다음과 같다.
2. 레퍼런스
1번의 과정에서 객체를 생성하면 힙 공간에 생성되고
item이라는 변수 자체에는 힙공간에 생성된 주소값이 담긴다고 하였다.
그 예로 만약 다음과 같이 코드를 짜면 무엇이 출력될까?
public class Item{
private String name;
private int price;
}
public class main{
public static void main(String[] args){
Item item=new Item();
item.name="apple";
item.price=1000;
System.out.println(item);
}
}
만약 1번의 개념을 알지 못한다면
item의 정보가 쭉 출력되는 것을 생각할 것이다.
하지만 실제로 출력해보면 그 객체가 가지 주소값만 출력된다.
이러한 방식으로 생성한 객체의 주소값을 담는 것을 레퍼런스라고 한다.
3. 자료형이 같은 복수의 객체 생성
만약 1번의 item 객체를 여러개 생성하면 어떻게 될까?
다음과 같이 코드를 짰다고 생각해보자.
public class Item{
private String name;
private int price;
}
public class main{
public static void main(String[] args){
int a=1;
int b=1;
Item item1=new Item();
Item item2=new Item();
if(a==b){
System.out.println("a==b")
}else{
System.out.println("a!=b");
}
if(item1==item2){
System.out.println("item1==item2");
}else{
System.out.println("item1!=item2");
}
}
}
위와 같이 코드를 짜고 돌려보면
int를 비교한 첫번째 조건문에서는 a==b가 출력되고
객체를 비교한 두번째 조건문에서는 item1!=item2가 출력될 것이다.
이렇게 차이가 나는 이유는 각 자료형 타입이 다르다는 데 있다.
int를 담은 a와 b는 기본형(primitive) 타입이므로 a,b라는 변수를 만들어 값을 넣으면
각 변수 안에 값 그 자체가 들어가게 된다.
때문에 a==b를 했을 때 각 변수에 들어가 있는 값은 1이므로 같다고 나오는 것이다.
하지만 item1과 item2는 new키워드를 통해 생성하면
각 변수들에는 각각의 주소 값이 들어가게 된다.
때문에 item1==item2를 했을 때
두 변수에는 각각 생성된 객체가 있고 두 객체는 메모리 주소가 다르기 때문에
같지 않다고 출력되는 것이다.
만약 기본 자료형과 레퍼런스 자료형의 차이에 대해 더 알고싶다면 정리해 놓은 글이 따로 있으니
참고하기를 바란다.
4. null과 NullPointerException
우리가 JAVA로 프로그래밍을 하다보면 정말 지겹게 마주치는 에러가 있는데
바로 NullPointerException이다.
이 NullPointerException이라는 녀석을 파헤치기 위해서 먼저 null이 무엇인지 알아야 한다.
null이란 우선 말 그대로 아무것도 없는 값이다.
비어있는 값이라 생각하면 될 것 같다.
이러한 null을 우리는 변수 안에 넣을 수 있는데
예제를 통해 한번 살펴보자.
public class Item{
private String name;
private int price;
}
public class main{
public static void main(String[] args){
Item item=new Item();
item.name="apple";
item.price=1000;
System.out.println(item.name);
item=null;
System.out.println(item.name);
}
}
위 코드는 item이라는 변수를 생성하고 한번 확인차 출력한 뒤에
여기에 null을 넣고 다시 출력해보는 예제이다.
위 코드를 실행하면 첫번째 출력은 잘 출력되지만
두번째 출력에서 NullPointerException 에러가 뜨는 것을 볼 수 있다.
왜 에러가 뜬 것일까?
우리가 처음에 item에 new키워드를 통해 객체를 생성해 줬을 때
힙 공간에 객체 주소가 담기고 여기에 null을 넣어주었다.
그리고 null을 넣었을 때 item이라는 변수는 더 이상 주소값을 가지고 있지 않는데
여기서 item.name을 하여 item 안의 값을 쓰려고 하니
name을 어디서 가져오라고 하는 건지 모르겠다며 에러를 뿜는 것이다.
여담으로 처음에 item 변수안에 담겼던 객체는 이 객체를 참조하고 있던
item변수가 이제 더이상 자신을 참조하고 있지 않고
아무도 자신을 가리키는 녀석이 없으니 시간이 지나면
가비지컬렉터(GC)의 회수 대상이 될 것이다.
Reference
이 포스팅은 아래의 강좌를 참고하여 만들어졌습니다.
- 자바 프로그래밍 입문 강좌 (renew ver.) - 초보부터 개발자 취업까지!!
https://www.inflearn.com/course/%EC%8B%A4%EC%A0%84-%EC%9E%90%EB%B0%94_java-renew/dashboard
'Language > Java' 카테고리의 다른 글
[Java]SHA256 암호화(Encrypt) 정리 및 예제 (0) | 2020.09.10 |
---|---|
[Java]생성자와 소멸자, this키워드 개념 정리 및 예제 (0) | 2020.09.07 |
[Java]접근제어자(Access Modifier) 개념 정리 (0) | 2020.08.26 |
[Java]메소드(Method)와 오버로딩(Overloading)의 사용법 및 예제 (0) | 2020.08.26 |
[Java]클래스 제작과 객체 생성하기 예제 (0) | 2020.08.26 |