ggoggo
참조타입 본문
데이터 타입 분류
자바의 데이터 타입에는 크게 기본타입(primitive type)과 참조 타입(reference type)이 있다.
- 참조 타입이란
- 객체의 번지를 참조하는 타입으로 배열, 열거 클래스, 인터페이스 타입을 말한다.
기본 타입으로 선언된 변수와 참조 타입으로 선언된 변수의 가장 큰 차이점은 저장되는 값이 무엇이냐이다.
기본타입을 이용해 선언된 변수는 실제 값을 변수 안에 저장하지만,
참조타입을 이용해 선언된 변수는 메모리의 번지를 값으로 갖는다.
추가적으로 변수가 스택 영역에 생성되고,
객체는 힙 영역에 생성된다는 것을 알아두자!
메모리 사용 영역
java.exe로 JVM이 시작되면 JVM은 운영체제에서 할당받은 메모리 영역(Runtime Data Area)을
아래와 같이 세부 영역으로 구분해 사용한다.
메소드(Method) 영역
- 코드에서 사용되는 클래스(~.class)들을 클래스 로더로 읽어 클래스별로 런타임 상수풀(runtime constant pool), 필드(field) 데이터, 메소드(method) 데이터, 메소드 코드, 생성자(constructor) 코드 등을 분류해서 저장한다.
- = 로딩된 클래스 바이트 코드 내용을 분석 후 저장
- 메소드 영역은 JVM이 시작할 때 생성한다.
- 모든 스레드가 공유하는 영역이다.
힙(Heap) 영역
- 객체와 배열이 생성되는 영역
- 생성된 객체와 배열은 JVM 스택 영역의 변수나 다른 객체의 필드에서 참조한다.
- 참조하는 변수나 필드가 없다면 의미없는 객체이므로 JVM은 Garbage Collector를 실행시켜 쓰레기 객체를 힙영역에서 자동으로 제거한다.
- JVM이 시작할 때 생성한다.
JVM 스택(Stack) 영역
- 각 스레드마다 하나씩 존재하며 스레드가 시작될 때 할당된다.
- 자바 프로그램에서 추가적으로 스레드를 생성하지 않았다면 main 스레드만 존재하므로 JVM 스택도 하나!이다.
- JVM 스택은 메소드를 호출할 때마다 프레임(frame)을 추가(push)하고 메소드가 종료되면 해당 프레임을 제거(pop)하는 동작을 수행한다.
변수가 스택영역에 저장되는 과정을 예시로 살펴보자
char v1 = 'A'; //(1)
if(v1=='A'){
int v2 = 100; //(2)
double v3 = 3.14; //(3)
}
boolean v4 = true; //(4)
변수는 선언된 블록안에서만 스택에 존재하고 블록을 벗어나면 스택에서 제거된다.
따라서 저 상황에서 스택은
[(1)] => [(1), (2), (3)] => [(1), (4)]
실행마다 이렇게 변화한다.
if문을 빠져나갈 시 (2),(3)이 스택에서 pop되는 것을 확인할 수 있다.
참조타입을 예로 들면
int[] scores = [10,20,30];
위 코드의 scores는 배열이므로 참조타입이다.
따라서 스택영역에서 scores는 5번지를 갖게되고
5번지는 힙 영역의 [10,20,30] 배열을 가리킨다.
참고로 자바에서는 배열을 객체로 취급한다.!
배열
배열이란?
- 같은 타입(자료형)의 데이터를 연속된 공간에 저장하는 자료구조
- 각 데이터 저장 위치는 인덱스('0'부터 시작)를 부여해 접근한다.
- 배열을 선언할 때 크기를 지정해야 하며, 나중에 그 크기를 변경할 수 없다.
- 특정한 값으로 초기화하지 않은 배열 안의 데이터를 참조하면 Null Pointer Exception이 발생한다.
- 배열 변수는 참조변수이므로 배열이 생성되기 전 null로 초기화가 가능하다. 이때 데이터를 참조하면 Null Pointer Exception 발생!
배열의 장점
- 중복된 변수 선은을 줄이기 위해 사용한다.
- 반복문을 이용해 데이터 요소들을 쉽게 처리할 수 있다.
String
- 자바는 문자열을 String 변수에 저장한다.
- String 변수에 문자열을 저장하려면 큰 따옴표("")로 감싼 문자열 리터럴을 대입하면 된다.
- String은 참조타입이므로 문자열은 String 객체(in 힙 영역)로 생성되고 변수(in 스택 영역)는 String 객체를 참조한다.
문자열 리터럴로 생성하느냐,
new 연산자로 생성하느냐에 따라 비교 연산자의 결과가 달라질 수 있다.
아래의 예시를 살펴보자
String name1 = "김채원";
String name2 = "김채원";
String name3 = new String("김채원");
name1과 name2는 동일한 문자열 리터럴로 생성된 객체를 참조하기 때문에
name1==name2는 true이다.
하지만 name3는 new 연산자로 힙영역에 String 객체를 별도로 생성했기 때문에
name1 ==name3는 false이다.
문자열만을 비교할때는 String 객체의 equals() 메소드를 사용하면 된다!
boolean result = str1.equals(str2); //=> true or false
만약 변수가 String 객체를 참조하였으나, 변수에 null을 대입해 더이상 String 객체를 참조하지 않는다면
JVM은 참조되지 않은 객체를 쓰레기 객체로 취급하여
Garbage Collector를 구동시켜 메모리에서 자동 제거한다.
'3-2 > JAVA' 카테고리의 다른 글
예외 처리와 파일 입출력 (0) | 2022.10.14 |
---|---|
"" 와 ''의 차이.. (0) | 2022.10.07 |
length, length(), size()의 차이 (0) | 2022.10.07 |
2. 출력과 변수(3) (0) | 2022.09.16 |
2. Java 프로그래밍 기초 (2) (0) | 2022.09.15 |