본문 바로가기
Programming Language/Java

[Java/개념] 데이터 타입 - 기본 타입(Primitive type)과 참조 타입(Reference type)

by wo__ongii 2024. 10. 10.
728x90
반응형

자바에서 데이터 타입은 크게 기본 타입(Primitive Type)과 참조 타입(Reference Type) 두 가지로 나눌 수 있다.

1. 기본 타입 (Primitive Type)

기본 타입은 자바에서 값 그 자체를 저장하는 타입으로, 자주 사용되는 데이터 유형들을 직접 다룬다. 기본 타입에는 다음과 같은 것들이 포함된다

  • 정수형: byte, short, int, long
  • 실수형: float, double
  • 문자형: char
  • 논리형: boolean

기본 타입의 변수는 선언된 값이 메모리 상에서 직접 저장되며, 이에 따라 해당 값에 빠르게 접근할 수 있다. 아래 코드에서 age와 price는 스택(Stack) 영역에 실제 값이 저장된다.

int age = 25;
double price = 100.5;

 

2. 참조 타입 (Reference Type)

참조 타입은 객체(Object)의 메모리 주소(번지)를 저장하는 타입으로, 객체를 참조하기 위한 용도로 사용된다. 참조 타입에는 배열, 열거형(Enum), 클래스, 인터페이스 등이 포함된다. 아래 코드에서 name과 hobby는 힙(Heap) 영역에 있는 String 객체를 참조하고 있으며, 스택에는 해당 객체의 주소 값만 저장된다. 이러한 특성 때문에 참조 타입 변수는 객체의 주소를 통해 객체에 접근한다고 표현한다

 

String name = "aaa";
String hobby = "정리";

 

기본 타입과 참조 타입의 차이

메모리상에서 변수는 스택 영역에 생성되고 객체는 힙 영역에 생성되게 된다. 기본 타입 변수는 값 자체를 스택 영역에 저장하고, 참조 타입 변수는 객체의 주소를 저장하여 해당 주소를 통해 힙 영역의 실제 객체에 접근한다.

 

 

3. 메모리 구조와 변수의 저장 위치

java.exe로 JVM이 시작되면 JVM은 운영체제에 할당받은 메모리 영역(Runtime Data Areas)을 세부 영역으로 구분해서 사용한다.

1) 메소드(Method) 영역

JVM이 시작될 때 생성되며, 모든 스레드가 공유하는 영역이다. 코드에서 사용되는 클래스(~.class)들을 클래스 로더로 읽어 클래스별로 클래스 정보, 필드, 메소드 데이터, 그리고 런타임 상수풀 등으로 분류해서 저장된다.

 

2) 힙(Heap) 영역

객체와 배열이 생성되는 영역이다. 힙 영역에 생성된 객체와 배열은 JVM 스택 영역의 변수나 다른 객체의 필드에서 참조한다. 참조가 사라진 객체는 가비지 컬렉터(Garbage Collector)에 의해 힙 영역에서 자동으로 제거된다.

3) JVM 스택(Stack) 영역

각 스레드마다 하나씩 존재하며 스레드가 시작될 때 할당된다. 메소드가 호출될 때마다 프레임(Frame)을 추가(push)하고, 메소드가 종료되면 해당 프레임을 제거(pop)하는 동작을 수행한다. 기본 타입 변수와 참조 타입 변수는 모두 스택에 저장되지만, 참조 타입은 실제 객체가 아닌 주소만 저장한다.

int[] scores = {10,20,30};

 

배열 변수인 scores는 스택 영역에 생성되지만 실게 10,20,30을 갖는 배열은 힙 영역에 생성된다. 배열 변수 scores에는 배열의 힙 영역의 주소가 저장된다.

 

또한 변수는 선언된 블록 안에서만 스택에 존재하고 블록을 벗어나면 스택에서 제거된다.

//실행 1
char v1 = 'A';

//실행 2
if(v1=='A'){
    int v2 = 100;
    double v3 = 3.14;
}

//실행 3
boolean v4 = true;

 

예제 코드에서 선언된 변수는 실행 순서에 따라 스택에 생성되고 소멸된다. 이 때 실행 2의 v2, v3은  if 블록 내부가 실행되고 있을 때만 스택 영역에 존재하고 실행 흐름이 if 블록을 빠져나가면 소멸된다.

 

4. 참조 타입 변수의 연산 (==, !=)

기본 타입 변수의 ==와 != 연산은 값 자체를 비교하지만, 참조 타입 변수는 객체의 메모리 주소를 비교한다. 동일한 객체를 참조하면 == 연산의 결과는 true를 반환하고, 다른 객체를 참조하면 false를 반환한다.

//스택 영역에는 refVar1 refVar2 refVar3 생성
//힙 영역에는 객체1, 객체2 생성
//각각 refVar1은 객체1 참조, refVar2, refVar3은 객체2 참조

refVar1 == refVar2  // false
refVar1 != refVar2  // true

refVar2 == refVar3  // true
refVar2 != refVar3  // false

 

5. null과 NullPointerException

참조 타입 변수는 객체를 참조하지 않는 상태일 때 null 값을 가질 수 있다. null도 초기값으로 사용할 수있기 때문에 null로 초기화된 참조 변수는 스택 영역에 생성된다. 

//스택 영역에 refVar1, refVar2 생성
//힙 영역에 객체1 생성
//refVar1은 객체1 참조하는 중

refVar1 == null  // false
refVar1 != null  // true

refVar2 == null  // true
refVar2 != null  // false

 

자바는 실행 도중 발생하는 오류를 예외(Exception)라고 부른다. 참조 변수를 사용하면서 가장 많이 발생하는 예외 중 하나로 NullPointException이 있다. 이는 참조 타입 변수를 잘못 사용 시 발생하며, null 값을 참조하는 변수를 통해 객체에 접근하려 할 때 발생한다.

int[] intArray = null;
intArray[0] = 10; //NullPointException

위 예시 코드를 보면 intArray는 배열 타입 변수이므로 참조 타입 변수이며 null로 초기화된 상태이다. 이 상태에서 intArray[0]에 10을 저장하려고 하면 NullPointException이 발생하는데, 이유는 intArray[] 변수가 참조하는 배열 객체가 없기 때문이다. 대처 방법은 이 변수를 추적해서 객체를 참조하도록 수정해야 한다.

6. String 타입

String은 자바에서 많이 사용하는 참조 타입 중 하나이다. 문자열 리터럴이 동일하다면 String 객체를 공유하지만, new 연산자를 사용해 객체를 생성하면 별도의 메모리에 할당된다.

String str1 = "hello";
String str2 = "hello";
String str3 = new String("hello");

System.out.println(str1 == str2);  // true (동일 객체)
System.out.println(str1 == str3);  // false (다른 객체)

 

문자열 비교 시에는 ==보다는 equals() 메소드를 사용하는 것이 좋다. equals()는 객체의 참조 값이 아닌 내용 자체를 비교한다.

if (str1.equals(str3)) {
    System.out.println("str1과 str3의 문자열이 동일합니다.");
}

 

[예시 코드]

public class Example{
	public static void main(String[] args){
    	String strVar1 = "aaa";
        String strVar2 = "aaa";
        
        if(strVar1 == strVar2){
        	System.out.println("strVar1과 strVar2 참조값 같음");
        }else{
        	System.out.println("strVar1과 strVar2 참조값 다름");
        }
        
        if(strVar1.equals(strVar2)){
        	System.out.println("strVar1과 strVar2 문자열 같음");
        }
        
		String strVar3 = new String("bbb");
        String strVar4 = new String("bbb");
        
		if(strVar3 == strVar4){
        	System.out.println("strVar3과 strVar4 참조값 같음");
        }else{
        	System.out.println("strVar3과 strVar4 참조값 다름");
        }
        
        if(strVar3.equals(strVar4)){
        	System.out.println("strVar3과 strVar4 문자열 같음");
        }   
    }
}

/*
결과 =
strVar1과 strVar2 참조값 같음
strVar1과 strVar2 문자열 같음
strVar3과 strVar4 참조값 다름
strVar3과 strVar4 문자열 같음

*/

 

 

 

 

 

 

[참고문헌: 이것이 자바다

이미지 출처: https://twil.weekwith.me/2%EA%B8%B0/%EC%A0%95%EC%84%A0%EB%AF%B8/2021-09-05-javascript-01/, https://youngbae10000.tistory.com/4]

 

728x90
반응형