-
[Java] 참조 타입과 참조 변수언어/Java 2020. 12. 27. 20:44
기본 타입과 참조 타입
자바는 크게 기본 타입(primitive type)과 참조 타입(reference type)으로 분류됩니다.
데이터 타입 기본 타입 참조 타입 정수 타입 배열 타입 byte 열거 타입 char 클래스 short 인터페이스 int long 실수 타입 float double 논리 타입 boolean 기본 타입은 실제 값을 변수에 저장하지만 참조 타입은 메모리의 주소값을 변수 안에 저장합니다.
기본 타입 변수
int a = 10;
참조 타입 변수
String n = "abcd";
메모리에서 이 변수들이 갖는 값을 그림으로 표현하면 아래와 같습니다.
메모리 사용 영역
JVM은 운영체제에서 할당 받은 메모리 영역을 아래와 같이 구분해서 사용합니다.
메소드 영역
메소드 영역은 JVM이 시작할 때 생성되고 모든 스레드가 공유하는 영역입니다. 메소드 영역에서는 코드엣 사용되는 class들을 클래스 로더로 읽어 클래스 별로 static field와 constant, method code, constructor code 등을 분류해서 저장합니다.
힙 영역
힙 영역은 객체와 배열이 생성되는 영역입니다. 여기에 생성된 객체와 배열은 JVM 스택 영역의 변수나 다른 객체의 필드에서 참조합니다. 만일 참조하는 변수나 필드가 없다면 의미없는 객체가 되기 때문에 JVM에서는 garbage collector로 처리를 합니다.
JVM 스택 영역
JVM 스택은 메소드를 호출할 때마다 frame을 추가하고 메소드가 종료되면 해당 프레임을 제거하는 동작을 수행합니다.
프레임 내부에는 로컬 변수 스택이 있는데 기본 타입 변수와 참조 타입 변수가 추가되거나 제거됩니다. 스택 영역에 변수가 생성되는 시점은 최초로 변수에 값이 저장될 때입니다. 변수는 선언된 블록 안에서만 스택에 존재하고 블록을 벗어나면 스택에서 제거됩니다.
참조 변수 비교
참조 변수에서 ==, != 로 비교하는 것은 값이 같은지 비교하는 것이 아니라 참조하는 메모리 주소값이 같은 지를 비교하는 것입니다.
int a = 10; int b = 10; a == b // 두 값이 10인지 비교 String s = "a"; String s1 = "a"; s == s1 // "a" 값 자체를 비교하는 것이 아닌, "a"를 참조하는 메모리 주소값이 같은지 비교
String 타입
문자열은 직접 변수에 저장되는 것이 아니라, 문자열은 String 객체로 생성되고 변수는 String 객체를 참조합니다.
자바는 문자열 리터럴이 동일하면 String 객체를 공유합니다.
String s = "a"; String s1 = "a"; // "a" 라는 String 객체가 메모리에 있는지 검색 // 없으면 "a" 라는 String 객체 생성 // s 변수에 "a" 메모리 주소값 할당 // s1 할당 하기 전, 메모리에 "a"가 있는지 검색 // 있으면 "a" 메모리 주소값을 s1에 할당
일반적으로 변수에 문자열을 저장할 경우에는 문자열 리터럴을 사용하지만 new 연산자를 사용해서 직접 String 객체를 생성할 수 있습니다. new 연산자는 힙 영역에 새로운 객체를 만들 때, 사용하는 연산자로 객체 생성 연산자라 합니다.
String s = "a"; String s1 = "a"; String s2 = new String("a"); s == s1 // true s == s2 // false s1 == s2 // false
참조 주소 비교가 아닌, 할당된 값 자체를 비교하고 싶으면 String 객체의 equals()를 사용하면 됩니다.
String s = "a"; String s1 = "a"; String s2 = new String("a"); s.equals(s1); s.equals(s2); s2.equals(s1);
아래와 같이 String 객체에 존재하는 초기값을 null로 대입하면 힙 영역에 존재하던 초기값은 메모리에서 자동 제거가 일어납니다.
String s = "a"; s = null;