[Java] 기초 - scope

이지연·2025년 12월 17일

개요

아래의 내용은 java_grammer 레파지토리 C02MethodClass 디렉터리에 저장되어있는 내용을 정리하였다.


변수의 유효 범위(Scope) 개요

변수는 선언된 위치(문맥)에 따라 유효 범위가 달라진다.
보통 자바에서는 크게 다음 3가지 범위로 나눌 수 있다.

  1. 클래스 변수 (static 변수)
  2. 객체 변수 (instance 변수)
  3. 지역 변수 (local 변수)

이를 코드로 살펴보면 이해가 빠르다.

public class C05Scope {
    static int v1 = 10; // 클래스 변수 (프로그램 전체 범위)
    int v2 = 20;        // 객체 변수 (객체 내부에서만 접근 가능)

    public static void main(String[] args) {
        int v3 = 10;     // 지역 변수 (해당 메서드 내에서만 유효)
    }
}
  • 클래스 변수(static)는 클래스 전역(어디서든)에서 접근 가능하다.
  • 객체 변수는 객체를 생성해야 접근할 수 있다.
  • 지역 변수는 선언된 메서드 내부에서만 유효하며, 메서드가 종료되면 사라진다.

즉, 변수의 생명주기는 선언된 위치메모리에 할당되는 영역에 의해 결정된다.


Call by Value (값에 의한 호출)

자바에서 기본형 자료형(primitive types)은 모두 값에 의한 호출 방식으로 전달된다.
즉, 변수의 값만 복사해서 전달되며, 원본 값에는 영향을 주지 않는다.

public static void main(String[] args) {
    int v3 = 10;
    scope1(v3);
    System.out.println(v3); // 10 출력
}

public static void scope1(int v3) {
    v3 = 30;
    System.out.println(v3); // 30 출력
}

출력 결과를 보면 다음과 같다.

30
10

scope1() 메서드 내부에서 v3를 30으로 바꾸었지만,
main 메서드에 있는 v3는 그대로 10인 이유는, 값(10)의 복사본만 전달되었기 때문이다.

즉, 서로 다른 메모리 공간을 사용하고 있으며,
scope1의 파라미터가 수정되어도 원본에는 아무런 영향이 없다.

📍 main() 호출 전
Stack: main() { int v3 = 10 }

📍 scope1(v3) 호출 시
Stack:
┌─────────────┐
│ scope1()    │ { int v3 = 10 ← 복사된 값 }
├─────────────┤
│ main()      │ { int v3 = 10 ← 원본 }
└─────────────┘

📍 scope1() 내부에서 v3 = 30 실행
Stack:
┌─────────────┐
│ scope1()    │ { int v3 = 30 ← 복사본만 변경 }
├─────────────┤
│ main()      │ { int v3 = 10 ← 원본 그대로 }
└─────────────┘

📍 scope1() 종료 후
Stack: main() { int v3 = 10 }

Call by Reference (참조에 의한 호출)

반면, 참조형 변수(reference type)는 객체의 실제 주소값(참조값)이 전달된다.
즉, 복사된 것이 아니라 원본 메모리 주소를 그대로 공유하게 된다.

C04Person2 p1 = new C04Person2();
p1.setName("kim");
p1.setEmail("kim@naver.com");
p1.setAge(15);
scope2(p1);
System.out.println(p1.returnPersonInfo());

scope2() 메서드 내부에서는 이렇게 정의되어 있다.

public static void scope2(C04Person2 person) {
    person.setName("lee");
    System.out.println(person.returnPersonInfo()); // lee
}

실행 결과는 다음과 같다.

이름은 lee, 이메일은 kim@naver.com, 나이는 15세 입니다.
이름은 lee, 이메일은 kim@naver.com, 나이는 15세 입니다.

메서드 내부에서 person.setName("lee")로 값을 변경하자,
원본 p1 객체의 name도 함께 바뀌었다.

이유는 메서드 매개변수 person이 p1이 참조하고 있는 같은 힙(Heap) 메모리 주소를 가리키고 있기 때문이다.

📍 main()에서 객체 생성
Stack: main() { C04Person2 p1 → 0x1000 }
Heap:  [0x1000] { name="kim", email, age=15 }

📍 scope2(p1) 호출 시
Stack:
┌─────────────┐
│ scope2()    │ { C04Person2 person → 0x1000 ← 같은 주소 }
├─────────────┤
│ main()      │ { C04Person2 p1 → 0x1000 ← 같은 주소 }
└─────────────┘
Heap:  [0x1000] { name="kim", email, age=15 }

📍 scope2() 내부에서 person.setName("lee")
Stack: 동일
Heap:  [0x1000] { name="lee", email, age=15 ← 원본 변경 }

📍 scope2() 종료 후
Stack: main() { C04Person2 p1 → 0x1000 }
Heap:  [0x1000] { name="lee", email, age=15 }

차이점

구분전달 방식전달되는 값원본 데이터 변경 여부
Call by Value값 복사변수의 값(예: 10)변경되지 않음
Call by Reference참조 복사객체의 주소값변경됨 (같은 메모리 참조)

자바의 모든 객체형(ex: String, 배열, 클래스)은 사실상 call by reference처럼 동작한다.
단, 자바에서는 모든 것이 “값에 의한 전달”이다.
즉, 참조형 변수의 “주소값”을 값으로 전달하고 있을 뿐이다.
이 부분은 면접에서도 자주 물어보는 개념이므로 정확히 이해해 두면 좋다.


요약

  • 클래스 변수(static)는 프로그램 전역에서 공유된다.
  • 객체 변수는 인스턴스별로 독립된 공간을 가진다.
  • 지역 변수는 메서드 내부에서만 유효하다.
  • 기본형 변수는 값 복사(call by value)로 전달된다.
  • 참조형 변수는 주소 복사(call by reference)로 전달되어, 원본 데이터가 수정될 수 있다.
profile
Eazy하게

0개의 댓글