Java

자바(JAVA)의 기본타입, 참조타입에 대한 쉬운 이해

개발하는 섭이 2023. 5. 13. 00:07

자바(Java)에서 사용하는 대표적인 두 종류의 타입을 알아보겠습니다.

 

자바(JAVA)에서는 기본타입(primitive type)참조타입(reference type)으로 나누어집니다.

 

우선 기본타입에는 정수, 실수, 문자 그리고 논리 타입이 있고,

참조타입에는 배열, 열거, 클래스 그리고 인터페이스가 있습니다.

 

기본타입byte, char, short, int, long, float, double, boolean의 변수는 값을 변수 안에 저장을합니다.

 

그와 달리 참조타입배열, 열거, 클래스, 인터페이스의 변수는 메모리의 번지 수를 변수 안에 저장합니다.

그래서 그 번지 수를 통해서 객체를 참조한다는 의미에서 참조타입이라고 불립니다.

 

우선, 윗글에서 설명한 내용에서 기본타입의 변수와 참조타입 변수가 저장을 하는 부분에 있어서

우리가 알아야 하는 것은 메모리의 사용 영역입니다.

 

아래에서 코드로 예시를 들어볼건데, 그 전에 각 메모리 영역의 역할을 보시면 훨씬 이해가 쉬울겁니다.

JVM으로 할당받은 메모리 영역은 메모리 영역, 힙 영역, 스택 영역으로 총 3가지로 나뉩니다.

 

간단히 말하자면,

메소드 영역은 코드에서 사용되는 클래스마다 정적 필드, 상수, 메소드, 생성자 코드 등을 저장하고,

힙 영역은 객체 또는 배열이 생성되는 영역입니다.

그리고 마지막 스택 영역은 기본타입 또는 참조타입의 변수가 추가되고 제거되는 영역입니다.

 

먼저 기본타입에 대한 코드 예시를 들어보겠습니다.

int a = 1;

if(a == 1) {
	int b = 2;
    double c = 3.0;
}

boolean d = false;

 

위에서 설명드렸다시피,

보여지는 코드에서 생성된 기본타입 변수들은 스택영역에 추가가 되고, 제거가 되는 영역입니다.

 

하지만 계속 스택 영역에 존재하는 것이 아니라,

선언 블록에서만 존재하고 블록을 벗어나 다음 코드블록을 읽는 순간

전에 선언된 블록에 있는 변수는 스택 영역에서 제거가 됩니다.

 

즉, int a = 1;을 선언했을 때 스택영역에 추가가 되지만

다음 블록인 if문 코드블록에 있는 변수들을 읽을 땐

if문의 코드블록안에 있는 변수는 스택 영역에 생성이 되고,

먼저 선언되었던 int a = 1; 은 스택영역에서 제거가 됩니다.

 

그럼 당연히 마지막 코드 블럭인 boolean d = false; 코드 블록이 선언되면

그 전에 생성되었던 변수 a, b, c는 스택 영역에서 제거가 되는 겁니다.


 

그럼 이제 참조타입에 대한 예시를 들어볼건데, 그 중에 아래의 배열 코드를 예시로 들어보겠습니다.

int[] number = {1, 2, 3};

우선, 자바에서는 배열은 객체로 취급을 한다는 점을 참고하고 보시기 바랍니다.

 

처음에 메모리 영역에 대해 설명드렸던 부분을 참고하고 보시면 이해가 쉬울겁니다.

 

선언된 변수 number는 스택영역에 저장이 되지만, 그 안에 배열은 별도로 힙 영역에 저장이 됩니다.

 

기본타입과는 달리 선언된 블록에서 값이 저장된 변수를 스택 영역에 저장하는 것이 아닌,

영역이 별도로 구분되어 저장이 되기 때문에

만일, 스택 영역에 number라는 변수의 번지 수가 1번지라고 가정을 했을 때

힙 영역에서 같은 1번지인 배열{1,2,3} 값을 참조해서 사용한다는 의미입니다.

 

자바를 배운지 얼마되지 않은 분들에게는 메모리 영역에 저장되는 차이점 외에

기본타입과 참조타입이 실제 개발에서 정확히 어떤 차이인지 구별이 어려울 수 있습니다.

 

차이점은 기본타입 간의 비교와 참조타입 간의 비교를 할 때 이해를 하실 수 있습니다.

 

먼저 기본타입의 경우는 스택 영역에 저장된 해당 변수의 값이 동일해서

아래의 코드의 조건문에서처럼 == 연산을 사용하면 결과 값은 true가 나오기 때문에

"a와 b는 같음"이라는 결과 값을 출력하게 됩니다.

int a = 3;
int b = 3;

if(a == b) {
	system.out.println("a와 b는 같음");
}else{
	system.out.println("a와 b는 다름");
}

 

하지만, 참조타입의 경우는 무조건 같다고 볼 수는 없습니다.

String name1 = "자바";
String name2 = "자바";

if(name1 == name2) {
	System.out.println("name1과 name2는 참조가 같음");
}else {
	System.out.println("name1과 name2는 참조가 다름");
}


String name1 = new String("자바");
String name2 = new String("자바");

if(name1 == name2) {
	System.out.println("name1과 name2는 참조가 같음");
}else {
	System.out.println("name1과 name2는 참조가 다름");
}

인스턴스화 시키기 전에는 문자열이 동일하기 때문에 == 연산으로 비교했을 땐,

결과 값은 true가 나오기 때문에 "name1과 name2는 참조가 같음" 이라는 값이 출력이 됩니다.

 

하지만 인스턴스화, 즉 new연산자를 통해 객체를 생성하여 만들 때는

name1과 name2는 서로 다른 String객체를 참조하게 되어

힙 영역에 각각 별도로 저장되기 때문에 "name1과 name2는 참조가 다름"이라는 결과 값이 출력됩니다.

 

이런 경우에는 객체 상관없이 내부 문자열을 비교하고 싶다면

아래와 같이 equals() 메소드를 사용하면

true로 결과 값이 나오기 때문에 "name과 name2는 문자열이 같음"이라는 결과 값이 출력됩니다.

if(name1.equals(name2) {
	System.out.println("name1과 name2는 문자열이 같음");
}