※이 글은 신용권 님의 혼자 공부하는 자바를 공부하며 참고한 글입니다.
자바의 타입은 크게 기본 타입(primitive type)과 참조 타입(reference type)으로 분류된다.
기본 타입에 대한 설명은 Chapter 01서 참조할 수 있다.
참조 타입
참조 타입이란 객체의 번지를 참조하는 타입으로 배열, 열거, 클래스 , 인터페이스를 말한다.
참조 타입인 배열, 열거, 클래스, 인터페이스 변수는 메모리의 번지를 변수 안에 저장한다.
번지를 통해 객체를 참조한다는 뜻에서 참조 타입이라고 부른다.
문자열 데이터를 저장하는 String 타입의 변수도 참조 타입 변수이다.
위 그림에서 메모리에서 기본 타입 변수와 참조 타입 변수가 어떻게 저장되는지 차이점을 볼 수 있다.
기본 타입 변수인 price, age의 경우 변수에 리터럴이 바로 저장이 되는 반면,
참조 타입 변수인 name, location의 경우 위에서 말했 듯 입력된 문자열 리터럴은 힙 영역 안의 임의의 번지에 저장되고
변수에는 해당 번지가 저장되어 있는 것을 확인할 수 있다.
힙 영역은 뭘까?
JVM이 사용하는 메모리 영역은 메서드 영역, 힙 영역, JVM 스택이 있다.
(JVM의 개념은 여기서 확인할 수 있다.)
메서드 영역이란
메소드 영역이란 JVM이 시작할 때 생성되고 모든 스레드가 공유하는 영역이다.
클래스들을 클래스 로더로 읽어 클래스별로 정적 필드와 상수, 메서드 코드, 생성자 코드 등을 분류해서 저장한다.
힙 영역이란
힙 영역이은 객체와 배열이 생성되는 영역이다.
만일 참조하는 변수나 필드가 없다면(null) 의미 없는 객체가 되기 때문에 JVM이 이것을 쓰레기로 취급하고 쓰레기 수집기(Garbage Collector)를 실행시켜 자동으로 제거한다.
JVM 스택 영역이란
JVM 스택은 메서드를 호출할 때마다 프레임을 추가하고 메서드가 종료되면 해당 프레임을 제거하는 동학을 수행한다.
스택 영역에 변수가 생성되는 시점은 초기화가 될 때, 즉 변수 초기화가 진행될 때이다. 변수는 선언된 블록 안에서만 스택에 존재하고 블록을 벗어나면 스택에서 제거된다.
참조 변수에서의 ==,!= 연산
참조 타입은 정확하게 따지면 앞에서 말했듯에 변수 안에 저장된 값이 리터럴이 아닌 리터럴을 저장하고 있는 번지수이다.
따라서 ==나!= 연산자를 사용하면 리터럴을 비교하는 게 아닌 번지수를 비교한다.
하지만 같은 값의 리터럴이라면 추가적으로 번지를 만들지 않고 동일한 리터럴을 가지고 있는 번지수를 불러온다.
//example code
String str = "안녕";
String str2 = "안녕";
String str3 = "안녕!";
- str에서 번지수가 100인 곳에 "안녕"이라는 문자 리터럴이 저장되었다.
- str2에서 "안녕"이라는 리터럴을 저장시킬 리터럴인 100이 이미 생성되어 있으므로 str2에는 str1과 동일하게
번지수 100이 들어간다. - str3은 str1과 str2에 들어있는 문자 리터럴과 값이 다르기에 다른 번지수가 생성된다.
numm과 NullPointerException
참조 타입 변수는 힙 영역의 객체를 참조하지 않는다는 뜻으로 null(널) 값을 가질 수 있다.
//example code
String refVar1 = "안녕";
String refVar2 = null;
refVar1 == null //false
refVar1 != null //true
refVar2 == null //true
refVar2 != null //flase
자바 프로그램 실행 도중에 발행하는 오류를 예외라고 한다.
참조 변수를 사용하면서 가장 많이 발생하는 예외 중 하나로 NullPointerException이 있다.
이 예외는 참조 타입 변수를 잘못 사용하면 발행한다.
만약 null 상태에서 있지도 않은 객체의 데이터(필드)나 메소드를 사용하는 코드를 실행하면 NullpointerException이 발생한다.
int[] intArray = null;
intArray[0] = 10; //error: NullPointerException
intArray 배열은 크기를 지정하지 않아 0번째에 대입할 수 없다.
new 연산자
new 연산자를 사용해서 직접 String 객체를 생성시킬 수도 있다.
new연산자는 힙 영역에 새로운 객체를 만들 때 사용하는 연산자로 객체 생성 연산자라고 한다.
//example code
String name1 = new String("홍길동");
String name2 = new String("홍길동");
원래라면 문자 리터럴이 같아 같은 번지수에 저장되어 name1과 name2에 같은 번지수가 대입되어야 한다.
하지만 new 연산자를 사용함으로써 서로 다른 번지수를 만들어 대입하였기에 다른 번지수가 대입되어있다.
따라서 new 연산자를 사용하여 변수 초기화를 한 name1, name2에 ==, != 연산자를 사용하게 되면
문자 리터럴은 같지만 name1, name2에는 서로 다른 번지수가 대입되어 있기에 서로 다르다고 출력된다.
String name1 = "홍길동";
String name2 = "홍길동";
String name3 = new String("홍길동");
//name1 == name2 != name3
동일한 String 객체이건 다른 String 객체이건 상관없이 내부 문자열을 비교하고 싶을 때에는 String객체의 equals() 메소드를 사용하면 된다.
String str1 = new String ("홍길동");
String str2 = new String ("홍길동");
boolean result = str1.equals(str2) //true
... 참조를 잃은 String 객체는 쓰레기 객체로 취급하고 쓰레기 수집기를 구동시켜 메모리에서 자동 제거된다.
읽어주셔서 감사합니다.
'📖혼자공부하는자바' 카테고리의 다른 글
Chapter 05-2 배열 (0) | 2022.11.26 |
---|---|
Chapter 06-1 객체 (0) | 2022.11.22 |
Chapter 04-3 반복문, break문, continue문 (0) | 2022.11.21 |
Hanghae Solution [Math.random()] (0) | 2022.11.18 |
Hanghae Solution [증감 연산자] (0) | 2022.11.18 |