Java에는 두 가지 근본적인 타입 범주가 있습니다. 기본형(값을 직접 저장하는 단순 값)과 참조형(객체로, 변수는 객체에 대한 참조/포인터를 보유)입니다. 이들은 메모리, 할당, 비교에서 매우 다르게 동작합니다.
8가지 기본형
;
;
;
;
;
;
;
;
기본형은 실제 값을 직접 저장하며, 크기가 고정되어 있고, null이 될 수 없으며, (지역 변수의 경우) 스택에 존재합니다. 빠르고 메모리 효율적입니다.
String name = "Ann"; // String 객체에 대한 참조
int[] arr = {1, 2, 3}; // 배열 객체에 대한 참조
List<String> list = new ArrayList<>(); // List 객체에 대한 참조
Person p = new Person("Bob"); // Person 객체에 대한 참조
참조 변수는 힙(heap)에 저장된 객체에 대한 참조(메모리 주소)를 보유하며 객체 자체를 보유하지 않습니다. null이 될 수 있습니다.
// 기본형 — 할당은 값을 복사함 (독립적)
int a = 5;
int b = a; // b는 복사본
b = 10; // a는 여전히 5
// 참조형 — 할당은 참조를 복사함 (둘 다 같은 객체를 가리킴)
int[] x = {1, 2, 3};
int[] y = x; // y는 같은 배열을 가리킴
y[0] = 99; // x[0]도 이제 99! (공유된 객체)
// == 는 기본형에 대해서는 값을 비교하지만, 객체에 대해서는 참조(identity)를 비교함
String s1 = new String("hi");
String s2 = new String("hi");
s1 == s2; // false — 서로 다른 객체 (서로 다른 참조)
s1.equals(s2); // true — equals() 는 내용을 비교함
이는 주요한 함정입니다. 객체에 대한 == 는 내용이 아니라 identity(같은 객체인가?)를 비교합니다 — 내용 비교에는 .equals()를 사용하십시오.
Integer boxed = 42; // Integer 는 int 의 객체 래퍼 (autoboxing)
int unboxed = boxed; // 다시 기본형으로 auto-unboxing
List<Integer> nums; // 컬렉션은 기본형이 아니라 객체를 필요로 함
각 기본형에는 래퍼 클래스(int→Integer 등)가 있어, 객체가 요구되는 곳(컬렉션, generics)에서 기본형을 사용할 수 있습니다.
기본형 대 참조형의 구분은 Java의 근본이며 많은 미묘한 버그와 동작의 원인입니다. 할당은 기본형에 대해서는 값을 복사하지만 객체에 대해서는 참조를 공유하며(따라서 공유된 객체를 수정하면 모든 참조에 영향을 미침), 특히 객체에 대해 == 가 identity를 비교한다는 점(고전적인 실수 — 내용 비교에는 .equals() 사용)이 중요합니다.
이를 이해하는 것은 비교의 정확성, 메서드 인자(객체는 사실상 참조 값으로 전달됨), null 처리(참조만 null이 될 수 있음), 성능(기본형이 더 가벼움)에 영향을 미칩니다.
이는 올바른 Java를 작성하기 위한 핵심 지식입니다.