[Java] 기본형 vs 참조형

손주현·2025년 4월 11일
0

Java 기초

목록 보기
13/13
post-thumbnail

자바에서는 변수를 선언할 때 기본형(Primitive Type)참조형(Reference Type)으로 나눌 수 있다.

기본형(Primitive Type)

  • int, long, double, boolean, char

  • 변수에 값 자체를 저장

  • 연산 가능, null 사용 불가

int a = 10;
int b = a; // 값 10을 복사

값을 복사했기 때문에 ab는 서로 영향을 주지 않는다.

참조형(Reference Type)

  • 클래스, 배열, 인터페이스 등

  • 변수에 객체나 배열의 메모리 주소(참조값) 저장

  • 연산 불가, null 사용 가능

Student s1 = new Student();
Student s2 = s1; // 참조값 복사

s1s2는 같은 객체를 가리킨다. 따라서 한 쪽에서 값을 바꾸면 다른 쪽에도 영향을 준다.

기본형 변수에는 직접 사용할 수 있는 값이 들어있지만 참조형 변수에는 위치(참조값)가 들어가 있다.
참조형 변수를 통해서 뭔가 하려면 결국 참조값을 통해 해당 위치로 이동해야 한다

자바에서 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)을 할 수 있다.
    메서드의 반환 기능을 사용해서 만들어진 객체의 참조값을 메서드 밖으로 반환하면 된다

변수의 초기화

  • 멤버 변수(필드): 클래스에 선언
  • 지역 변수: 메서드에 선언, 매개변수도 지역 변수의 한 종류
변수 종류자동 초기화초기값 예시
멤버 변수Oint=0, boolean=false, 참조형 = null
지역 변수X반드시 직접 초기화 필요
class Data {
    int x; // 자동 초기화: 0
    String str; // 자동 초기화: null
}

void method() {
    int y; // 초기화 안 하면 오류 발생
    System.out.println(y); // ❌
}

참조형의 null과 NullPointerException

참조형 변수는 아직 객체를 가리키지 않을 때 null로 초기화된다.

public class Data {
    int value;
}
Data data = null;
data.value = 0; // ❌ NullPointerException

null은 아무 객체도 가리키지 않기 때문에 .name과 같은 접근 시 예외 발생


GC (Garbage Collection)

자바에서는 더 이상 사용하지 않는 객체를 자동으로 정리(삭제)해주는 기능이 있다.
이것을 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);

실행 흐름 설명

  1. data = null;
  • data 변수는 null로 초기화되어 있어 아무 객체도 참조하지 않는 상태이다.
  • 출력 결과: 1. data = null
  1. data = new Data();
  • new Data()로 새로운 객체가 생성되고, 해당 객체의 참조값이 data 변수에 저장된다.
  • 이 시점에서 메모리 어딘가에 Data 인스턴스가 존재하고, data가 그 위치를 참조한다.
  • 출력 결과: 2. data = ref.Data@xxxxxx (참조값)
  1. data = null;
  • 다시 data 변수에 null을 할당하면, 기존에 참조하던 Data 객체와의 연결이 끊긴다.
  • 이제 아무도 그 객체를 참조하지 않게 되며, 더 이상 접근할 방법이 없다.
  • 출력 결과: 3. data = null

이 시점에 메모리 내부에서는 Data 객체는 여전히 메모리에 존재하지만, 참조하는 변수(data)가 없기 때문에 쓸모 없는 객체가 된다.
이러한 객체를 자바에서는 Garbage(쓰레기)로 판단한다.
GC(Garbage Collector)는 이러한 객체를 주기적으로 감지하고 메모리에서 자동으로 제거한다.

GC(Garbage Collection)의 특징

  • 수동 삭제 불필요
    개발자가 직접 free()delete를 호출할 필요 없음 (C/C++과의 차이점)

  • 참조가 끊긴 객체만 제거
    현재 어떤 변수도 참조하지 않는 객체만 GC 대상이 됨

  • 언제 작동할지 모름
    GC는 JVM이 알아서 적절한 시점에 실행함 (명시적 제어는 어려움)

  • null 할당은 힌트일 뿐
    변수에 null을 대입해도 GC가 바로 작동하진 않음

주의할 점

  • 참조가 하나라도 남아 있으면 GC 대상이 아님

  • 메모리 누수를 막기 위해 불필요한 참조는 null로 명시적으로 끊어주는 것이 좋을 때도 있음

  • 단, null을 썼다고 해서 GC가 즉시 작동하는 것은 아니다

profile
Clarinetist.dev

0개의 댓글