
Java의 변수 타입은 크게 두 가지로 나눌 수 있다.
int, long, double, boolean처럼 실제 값을 직접 변수에 저장한다. String, 배열(int[]), 클래스(Student student1)처럼 객체가 위치한 메모리 주소(참조값)를 저장한다. 즉,
int a = 10; // 변수 안에 값 10이 직접 저장됨
Student s = new Student(); // 변수 안에는 Student 객체의 참조값만 저장됨
int a = 10, b = 20;
int sum = a + b; // OK
Student s1 = new Student();
Student s2 = new Student();
s1 + s2; // 오류 발생!
단, 참조형 안에 있는 기본형 멤버 변수를 꺼내면 연산할 수 있다.
s1.grade = 100;
s2.grade = 90;
int sum = s1.grade + s2.grade; // OK
Java의 대원칙: 항상 변수에 들어있는 값을 복사해서 대입한다.
int a = 10;
int b = a;
a = 20;
System.out.println("a = " + a); // 20
System.out.println("b = " + b); // 10
a와 b는 값 자체를 따로 가지고 있으므로 영향을 주지 않는다.
Data dataA = new Data();
dataA.value = 10;
Data dataB = dataA; // 참조값 복사
dataA와 dataB는 같은 객체를 가리키게 된다. dataA.value = 20;
System.out.println(dataB.value); // 20
dataB.value = 30;
System.out.println(dataA.value); // 30
메서드 호출 시에도 동일하게 값이 복사되어 전달된다.
public static void main(String[] args) {
int a = 10;
changePrimitive(a);
System.out.println("a = " + a); // 10
}
static void changePrimitive(int x) {
x = 20;
}
a의 값 10이 복사되어 x에 전달된다. x를 바꿔도 a에는 영향이 없다.public static void main(String[] args) {
Data dataA = new Data();
dataA.value = 10;
changeReference(dataA);
System.out.println("dataA.value = " + dataA.value); // 20
}
static void changeReference(Data dataX) {
dataX.value = 20;
}
dataA의 참조값이 dataX에 복사된다. dataX를 통해 변경하면 dataA도 영향을 받는다.0 false nullclass InitData {
int value1; // 자동 초기화 → 0
int value2 = 10; // 명시적 초기화 → 10
}
public static void main(String[] args) {
int x; // 초기화하지 않으면 사용 불가
x = 5;
}
참조형 변수에는 객체의 위치가 들어가야 하지만, 아직 참조할 객체가 없을 때는 null을 넣을 수 있다.
Data data = null;
System.out.println(data); // null
null은 "아직 아무 객체도 참조하지 않는다"는 의미다. null 자체는 안전하게 변수에 저장될 수 있다. 하지만 null에 대해 객체처럼 접근하려 하면 문제가 발생한다.
Data data = null;
data.value = 10; // NPE 발생!
null은 실제 객체가 아니므로 그 안에 필드나 메서드가 존재하지 않는다. . (dot) 연산을 하면 NullPointerException이 발생한다. 실무에서 자주 발생하는 오류이므로, 항상
null체크를 습관화해야 한다.
Java는 메모리 관리를 자동으로 수행한다.
Data data1 = new Data();
data1 = null; // 기존 객체는 참조하는 변수가 없음 → GC 대상
즉, 개발자가 직접 free() 같은 메모리 해제를 하지 않아도 된다.
하지만 null을 잘못 다루면 GC가 처리하기 전에 NPE를 만나는 경우가 많다.