05-1 참조 타입과 변수
▶ 참조 타입 이름의 의미
기본 타입은 변수에 실제 값을 저장하지만, 참조 타입은 변수에 '메모리 주소'를 저장한다.
주소를 통해 객체를 참조한다는 뜻에서 '참조' 타입이라 부른다.
▶ 참조 타입(reference type)의 종류
배열 타입, 열거 타입, 클래스, 인터페이스
(String은 클래스에 속함)
int는 소문자로 쓰고 String은 대문자로 쓰는 이유도 타입이 기본 vs 참조로 다르기 때문!😯
⭐JVM의 메모리 사용 영역⭐
cf. JVM == 자바 가상 머신 / 하나의 컴퓨터라고 생각하면 됨
메소드 영역(Method Area)
- 클래스의 정보가 저장되는 공간
- JVM이 시작할 때 생성되고 모든 스레드가 공유하는 영역
- 자바는 특정 클래스가 사용되면 해당 클래스의 파일(*.class)를 읽어(=컴파일) 클래스에 대한 정보를 메소드 영역에 분류하여 저장한다.
힙(Heap)
- 인스턴스(배열, 객체)가 저장되는 공간
- new 키워드를 사용해서 만드는 인스턴스는 모두 힙 영역에 저장된다.
- 앞에서 '참조 타입'의 의미를 배웠는데 이때 참조 타입이 '참조하는 주소'가 바로 힙에 있는 객체의 주소이다.
호출 스택(Call Stack)
- 변수가 저장되는 공간
- 메서드가 호출되면 메서드 수행에 필요한 메모리 공간인 '프레임'을 할당받고 메서드가 종료되면 사용하던 프레임을 반환한다.
- 프레임 내부에는 로컬 변수 스택이 있는데, 초기화, 블럭 종료 등에 따라 변수가 pop, push된다.
∴ 호출 스텍 ⊃ 프레임 ⊃ 로컬 변수 스택
한줄 정리 : 메소드 영역 - 클래스 / 힙 - 객체 / 스택 - 변수
▶ 힙 & 호출 스택의 관계 이해
배열을 선언하면, 배열은 힙에 생성되고 변수는 호출 스택에 생성된다.
이때 변수가 참조하는 것은 힙에 생성된 배열(객체)의 주소이다.
Ex. String name = "Yonso"; 는 엄밀히 말하면 힙 영역에 생성된 "Yonso"객체의 주소를
스택 영역에 생성된 변수 name이 참조한다고 말할 수 있다.
=> 하지만 그냥 간단히 name 변수에 "Yonso"를 저장한다고 하는 것!
▶ 참조 변수의 ==, != 연산
앞에서 '왜 자바에서는 문자열을 비교할 때 ==가 아니라 .equals( )를 쓰냐'고 불평한 적이 있었는데,
그 이유를 여기에서 설명할 수 있다.
참조변수들 간의 ==, != 연산은 '참조하고 있는 주소가 같은가?' 즉, '동일한 객체를 참조하는가?'를 알아볼 때 사용된다.
즉, 문자열 비교에서 ==를 사용하면 문자열 비교가 아니라, 주소 비교를 하게 되는 것!
참조하고 있는 주소가 다르다고 해서 값까지 다른 것은 아니므로,
==를 사용하면, 값 자체는 동일하나 주소는 다르기 때문에 false가 나오는 오류가 발생할 수 있다.
public class compare {
public static void main(String[] args) {
// 값은 같지만 다른 주소를 참조하는 예시 (문자열 리터럴 & new로 생성된 문자열)
String s1 = "abcd";
String s2 = new String("abcd");
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
// cf. 자바는 문자열 리터럴이 같으면 같은 객체를 공유하도록 함
String s3 = "abcd";
String s4 = "abcd";
System.out.println(s3 == s4); // false
}
}
❗결론❗
String을 비교할 때는 .equals( )를 사용하자.
누가 왜 == 안쓰냐고 물어보면, ==는 주소를 비교하는 것이기 때문! 이라고 대답하면 됨.
▶ null
참조타입 변수는 어떤 인스턴스도 참조하지 않는다는 의미에서 null값을 가질 수 있다.
null은 참조타입 초기화에서만 사용 가능하고, 기본형 변수 초기화에 사용하면 오류가 발생한다.
또한 int 변수를 생성하고 초기화하지 않으면 기본값으로 0을 갖듯이 null은 모든 참조타입의 기본값이다.
null로 초기화된 변수도 스택 영역에 생성되긴 한다. (그것이.. 변수니까.. 음!)
해당 변수가 null인지 알아보기 위해서는 == null 을 사용하면 된다.
만약 객체A를 참조하던 변수를 = null로 초기화하면 객체 A는 더이상 참조하는 것이 없으므로 gabage collector에 의해 자동으로 힙영역에서 제거된다.
▶ 참조와 포이터의 차이점
* 시작에 앞서, 지금은 GC나, 참조의 원리를 공부하는게 아니므로 이 단계에서는 '참조의 역할'을 이해하는 것을 목표로 하자.
- 포인터와 참조의 차이
포인터 : 객체가 저장된 메모리의 주소를 저장한다.
참조 : 객체의 정확한 주소에 관계없이 해당 객체를 가리킨다.
- 자바에서 참조를 사용하는 이유
자바에서는 포인터가 존재하지 않는다.
정확히 말하자면, 개발자가 접근할 수 없게 해놨다.
자바에서는 객체의 주소가 Garbage Collector에 의해 자동으로 바뀌기 때문에
주소 자체를 다루는 것은 굉장히 위험하다. (GC에 의해 추후 변경될 수 있기 때문)
따라서 주소를 알려주지 않고 참조를 사용하는 것이다.
'JAVA > 혼공자' 카테고리의 다른 글
[혼공자] Chapter 05-3 열거 타입 (0) | 2022.07.26 |
---|---|
[혼공자] Chapter 05-2 배열 (0) | 2022.07.23 |
[혼공자] Chapter 04. 조건문과 반복 (0) | 2022.07.21 |
[혼공자] Chapter 03. 연산자 (0) | 2022.07.21 |
[혼공자] Chapter 02. 변수와 타입 (0) | 2022.07.20 |