자바에서는 변수를 선언할 때 기본형(Primitive Type)과 참조형(Reference Type)으로 나눌 수 있다.
int, long, double, boolean, char 등
변수에 값 자체를 저장
연산 가능, null 사용 불가
int a = 10;
int b = a; // 값 10을 복사
값을 복사했기 때문에 a와 b는 서로 영향을 주지 않는다.
클래스, 배열, 인터페이스 등
변수에 객체나 배열의 메모리 주소(참조값) 저장
연산 불가, null 사용 가능
Student s1 = new Student();
Student s2 = s1; // 참조값 복사
s1과 s2는 같은 객체를 가리킨다. 따라서 한 쪽에서 값을 바꾸면 다른 쪽에도 영향을 준다.
기본형 변수에는 직접 사용할 수 있는 값이 들어있지만 참조형 변수에는 위치(참조값)가 들어가 있다.
참조형 변수를 통해서 뭔가 하려면 결국 참조값을 통해 해당 위치로 이동해야 한다
자바에서 String은 특별하다. String은 사실은 클래스이기 때문에 참조형이다.
그런데 기본형처럼 문자 값을 바로 대입할 수 있다.
문자열은 매우 자주 다루기 때문에 자바에서 특별하게 편의 기능을 제공한다.
자바는 항상 값을 복사해서 전달한다.
하지만 전달되는 값이 "실제 값"인지 "참조값"인지에 따라 결과가 달라진다.
void change(int x) {
x = 20;
}
int a = 10;
change(a);
System.out.println(a); // 10
→ 값만 복사되므로 원본 a는 변경되지 않음
public class Student {
String name;
int age;
int grade;
}
void change(Student s) {
s.grade = 100;
}
Student student = new Student();
student.grade = 90;
change(student);
System.out.println(student.grade); // 100
→ 참조값이 복사되었기 때문에 같은 객체를 공유함. 내부 상태 변경 가능
자바에서 메서드의 매개변수(파라미터)는 항상 값에 의해 전달된다.
그러나 이 값이 실제 값이냐, 참조(메모리 주소)값이냐에 따라 동작이 달라진다.
public static void main(String[] args) {
Student student1 = createStudent("학생1", 15, 90);
Student student2 = createStudent("학생2", 14, 95);
printStudent(student1);
printStudent(student2);
}
static void printStudent(Student student) {
System.out.println("이름:" + student.name + " 나이:" + student.age + " 성적:" + student.grade);
}
static Student createStudent(String name, int age, int grade) {
Student student = new Student();
student.name = name;
student.age = age;
student.grade = grade;
return student;
}
createStudent()라는 메서드를 만들고 객체를 생성하는 부분도 이 메서드안에 함께 포함했다.return)을 할 수 있다.| 변수 종류 | 자동 초기화 | 초기값 예시 |
|---|---|---|
| 멤버 변수 | O | int=0, boolean=false, 참조형 = null |
| 지역 변수 | X | 반드시 직접 초기화 필요 |
class Data {
int x; // 자동 초기화: 0
String str; // 자동 초기화: null
}
void method() {
int y; // 초기화 안 하면 오류 발생
System.out.println(y); // ❌
}
참조형 변수는 아직 객체를 가리키지 않을 때 null로 초기화된다.
public class Data {
int value;
}
Data data = null;
data.value = 0; // ❌ NullPointerException
→ null은 아무 객체도 가리키지 않기 때문에 .name과 같은 접근 시 예외 발생
자바에서는 더 이상 사용하지 않는 객체를 자동으로 정리(삭제)해주는 기능이 있다.
이것을 GC(Garbage Collection, 가비지 컬렉션)이라고 부른다.
Data data = null;
System.out.println("1. data = " + data);
data = new Data();
System.out.println("2. data = " + data);
data = null;
System.out.println("3. data = " + data);
data = null;data 변수는 null로 초기화되어 있어 아무 객체도 참조하지 않는 상태이다.1. data = nulldata = new Data();new Data()로 새로운 객체가 생성되고, 해당 객체의 참조값이 data 변수에 저장된다.Data 인스턴스가 존재하고, data가 그 위치를 참조한다.2. data = ref.Data@xxxxxx (참조값)data = null;data 변수에 null을 할당하면, 기존에 참조하던 Data 객체와의 연결이 끊긴다.3. data = null이 시점에 메모리 내부에서는 Data 객체는 여전히 메모리에 존재하지만, 참조하는 변수(data)가 없기 때문에 쓸모 없는 객체가 된다.
이러한 객체를 자바에서는 Garbage(쓰레기)로 판단한다.
GC(Garbage Collector)는 이러한 객체를 주기적으로 감지하고 메모리에서 자동으로 제거한다.
수동 삭제 불필요
개발자가 직접 free()나 delete를 호출할 필요 없음 (C/C++과의 차이점)
참조가 끊긴 객체만 제거
현재 어떤 변수도 참조하지 않는 객체만 GC 대상이 됨
언제 작동할지 모름
GC는 JVM이 알아서 적절한 시점에 실행함 (명시적 제어는 어려움)
null 할당은 힌트일 뿐
변수에 null을 대입해도 GC가 바로 작동하진 않음
참조가 하나라도 남아 있으면 GC 대상이 아님
메모리 누수를 막기 위해 불필요한 참조는 null로 명시적으로 끊어주는 것이 좋을 때도 있음
단, null을 썼다고 해서 GC가 즉시 작동하는 것은 아니다