자바의 타입은 크게 기본 타입(primitive type)과 참조 타입(reference type)으로 분류됩니다. 기본 타입은 정수, 실수, 문자, 논리 리터럴을 저장하는 타입을 말합니다. 참조 타입은 객체 번지를 참조하는 타입으로 배열, 열거, 클래스, 인터페이스를 말합니다.
기본 타입과 참조 타입
기본 타입으로 선언된 변수와 참조 타입으로 선언된 변수의 차이점은 저장되는 값입니다. 기본 타입인 byte, char, short, int, long, float, double, boolean 변수는 실제 값을 변수 안에 저장하지만, 참조 타입인 배열, 열거, 클래스, 인터페이스 변수는 메모리의 번지를 변수 안에 저장합니다. 번지를 통해 객체를 참조한다는 뜻에서 참조타입이라고 부릅니다. 기본 타입은 미리 크기가 정해져있기 때문에 메모리를 할당하고 값을 저장할 수 있지만 참조 타입은 크기가 정해져있지 않기 때문에 위치를 나타내는 변수를 할당하고 그 변수에 할당되는 위치를 나타내는 번지를 저장합니다.
메모리 사용 영역
JVM(Java Virtual Machine)이 사용하는 메모리 영역에 대해 알아보겠습니다. JVM은 운영체제에서 할당받은 메모리 영역을 다음과 같이 세부 영역으로 구분해서 사용합니다.
메소드 영역
메소드 영역은 JVM이 시작할 때 생성되고 모든 스레드가 공유하는 영역입니다. 메소드 영역에는 코드에서 사용되는 클래스들을 클래스 로더로 읽어 클래스별로 정적필드와 상수, 메소드 코드, 생성자 코드 등을 분류해서 저장합니다.
힙 영역
힙 역역은 객체와 배열이 생성되는 영역입니다. 여기에 생성된 객체와 배열은 JVM 스택 영역의 변수나 다른 객체의 필드에서 참조합니다. 만일 참조하는 변수나 필드가 없다면 의미없는 객체가 되기 때문에 JVM이 이것을 쓰레기로 취급하고 쓰레기 수집기(Garbage Collector)를 실행시켜 자동으로 제거합니다.
JVM 스택 영역
JVM 스택은 메소드를 호출할 때마다 프레임(Frame)을 추가하고 메소드가 종료되면 해당 프레임을 제거하는 동작을 합니다. 프레임 내부에는 로컬 변수 스택이 있는데, 기본 타입 변수와 참조 타입 변수가 추가되거나 제거됩니다. 스택 영역에 변수가 생성되는 시점은 초기화가 될 때, 즉 최초로 변수에 값이 저장될 때입니다. 변수는 선언된 블록 안에서만 스택에 존재하고 블록을 벗어나면 스택에서 제거됩니다.
JVM에서 메모리를 사용하는 것은 굉장히 중요한 내용이고 알아둘 필요가 있습니다. 헷갈리기도하고 쉽지는 않지만 중요한 몇가지만 기억하시면 됩니다. 메소드 영역은 미리 정해진 것들이 들어가는 자리이고 스택영역은 크기가 정해진 변수들이 생성되고 삭제되는 장소이며 힙영역은 크기가 정해지지 않은 클래스 같은 참조 변수들이 저장되는 자리입니다.
참조 변수의 ==, != 연산
기본 타입 변수의 ==, != 연산은 변수의 값이 같은지, 아닌지를 조사하지만 참조 타입 변수들 간의 ==, != 연산은 동일한 객체를 참조하는지, 다른 객체를 참조하는지 알아볼 때 사용됩니다. 동일한 번지 값을 가지고 있다는 것은 동일한 객체를 참조한다는 의미입니다. 따라서 동일한 객체를 참조학 있을 경우 == 연산의 결과는 true이고 != 연산의 결과는 false입니다. 이는 참조변수는 값을 저장하지 않고 위치주소를 가지고 있기 때문입니다. 스택영역에 주소를 저장하는 변수를 만들고 힙영역에 참조변수를 생성하고 스택영역에 있는 변수에 힙영역의 주소를 저장하는 것입니다.
null과 NullPointerException
참조 타입 변수는 힙 영역의 객체를 참조하지 않는다는 뜻으로 null값을 가질 수 있습니다. null 값도 초기값으로 사용할 수 있기 때문에 null로 초기화된 참조변수는 값으로 null을 가지고 힙영역에 생성을 하지 않습니다.
자바는 프로그램 실행 도중에 발생하는 오류를 예외(exception)라고 부릅니다. 예외는 사용자의 잘못된 입력으로 발생할 수도 있고, 프로그래머가 코드를 잘못 작성해서 발생할 수도 있습니다. 참조변수를 사용하면서 가장 많이 발생하는 예외 중 하나로 NUllPointerException이 있습니다. 이 예외는 참조 타입 변수를 잘못 사용하면 발생합니다. 참조변수가 null을 가지고 있을 경우에는, 참조객체가 없으므로 변수를 통해 객체를 사용할 수 없습니다. 만약에 null 상태에서 있지도 않은 객체의 필드나 메소드를 사용하는 코드를 실행하면 NullPointerException이 발생합니다.
String 타입
자바는 문자열을 String 변수에 저장합니다. String 타입은 기본타입처럼 사용되기 때문에 기본타입으로 착각할 수 있지만 String은 참조타입입니다. String의 대문자 S로 시작되기 때문에 클래스이며 참조변수입니다. 다른 클래스와 달리 일반 기본 타입 변수들처럼 사용할 수 있습니다. 이는 문자열이 굉장히 많이 쓰이는 타입이기 때문입니다. 문자열은 크기가 정해져 있지 않기때문에 기본 타입의 변수가 될 수 없고 생성 시에 힙영역에 존재하게 됩니다. 일반적으로 변수에 문자열을 저장할 경우에는 문자열 리터럴을 사용하지만, new 연산자를 사용해서 직접 String 객체를 생성시킬 수도 있습니다. new 연산자는 힙 영역에 새로운 객체를 만들 때 사용하는 연산자로 객체 생성 연산자라고 합니다. String 타입을 문자열 리터럴로 생성하느냐 new 연산자로 생성하느냐에 따라 비교 연산자의 결과는 달라질 수 있습니다. 예제를 통해 살펴보도록 하겠습니다.
위의 예제에서 보면 String 타입인 str1과 str2에 모두 "홍길동"이라는 문자열을 넣습니다. 원래 str1과 str2는 다른 변수이지만 같은 리터럴을 저장하게되어 같은 주소를 저장하게 됩니다. 자바에서는 JVM이 메모리를 관리해서 같은 리터럴을 추가로 생성하지 않습니다. 그래서 같은 주소를 참조하게 되는 것입니다. 그러므로 str1과 str2는 같은 값을 가지며 같은 주소를 가진다는 의미는 하나의 객체를 가르킨다는 뜻이고 당연히 같은 값을 가집니다. str3와 str4는 new 연산자를 사용하여 값을 저장합니다. new 연산자는 힙영역에 변수를 생성합니다. 그래서 str3를 힙영역에 생성하고 그 값을 "이순신"으로 저장하게 됩니다. str4도 마찬가지로 작동합니다. str3와 str4는 각각 힙영역에 생성되었습니다. 그래서 서로 다른 주소를 갖게 되지만 같은 값인 "이순신"을 가지므로 값은 같게 됩니다. equals 메소드는 값을 비교할 때 사용하는 메소드입니다. 앞으로 참조변수에서 값을 비교할 때 많이 사용되는 메소드니 잘 지억해 두시기 바랍니다.
'프로그래밍 > Java 프로그래밍' 카테고리의 다른 글
자바의 배열과 향상된 for문 (0) | 2020.07.04 |
---|---|
자바의 배열 (0) | 2020.07.03 |
자바 반복문 (0) | 2020.07.01 |
자바 조건문 (0) | 2020.06.29 |
자바연산자와 연산식4 (0) | 2020.06.29 |