스코프 연습문제(눈으로)

류한선·2025년 6월 20일

실기연습-2

목록 보기
13/95

✅ 문제 1 – shadowing + static

public class Main {
    static int x = 10;

    public static void main(String[] args) {
        int x = x + 1;
        System.out.println(x);
    }
}

🔍 해설:

static int x = 10;
  • 클래스 레벨(static 변수)에서 x는 10으로 초기화됨.
int x = x + 1;
  • 문제 포인트: 오른쪽 x는 이 지역 변수 x를 참조하려고 하는데, 선언 이전이라서 아직 유효하지 않음!
  • 이 줄은 결국 자기 자신을 참조하려는 모순된 코드
  • 자바는 지역 변수에 대해 선언보다 먼저 사용 불가

❌ 결과: 컴파일 오류

variable x might not have been initialized


✅ 문제 2 – 메서드 내 지역 변수 vs 인스턴스 변수 (체크 this.a)

public class Main {
    int a = 1;

    public void test() {
        int a = a + 1;
        System.out.println(a);
    }

    public static void main(String[] args) {
        new Main().test();
    }
}
int a = 1;
  • 인스턴스 변수 a 선언
int a = a + 1;
public class Main {
    int a = 1;

    public void test() {
        int a = this.a + 1; // ✅ 멤버 변수 a를 명시적으로 사용
        System.out.println(a);
    }

    public static void main(String[] args) {
        new Main().test();
    }
}
  • 지역 변수 a 선언하려는데 오른쪽 a는 지역 스코프의 a를 참조하려 함
  • 하지만 이 시점에는 지역 변수 a가 아직 존재하지 않음
  • 따라서 인스턴스 변수 a에 접근하려면 this.a를 써야 했음

❌ 결과: 컴파일 오류

variable a might not have been initialized


✅ 문제 3 – 블록 중첩과 변수 가리기

public class Main {
    public static void main(String[] args) {
        int num = 3;
        {
            int num = num + 1;
            System.out.println(num);
        }
    }
}
int num = 3;
{
    int num = num + 1;
    System.out.println(num);
}
  • int num = num + 1; → 선언 중인 변수 num을 자기 자신으로 초기화하려는 코드
  • 선언되기 전이므로 num이 정의되지 않았다는 에러

❌ 결과: 컴파일 오류

variable num might not have been initialized


✅ 문제 4 – for 루프 안에서 변수 선언

public class Main {
    public static void main(String[] args) {
        int i = 0;
        for (int i = 0; i < 3; i++) {
            System.out.println(i);
        }
    }
}
int i = 0;
for (int i = 0; i < 3; i++) {
    System.out.println(i);
}
  • int i = 0; → 먼저 선언됨 (main 내부)
  • for (int i = ... → 같은 이름으로 또 선언하려 함 (블록 안이지만 같은 스코프로 인식됨)

❌ 결과: 컴파일 오류

variable i is already defined in method main(String[])


✅ 문제 5 – 지역 클래스 내부에서 변수 접근

public class Main {
    public static void main(String[] args) {
        int val = 10;
        class Local {
            void print() {
                System.out.println(val);
            }
        }
        new Local().print();
    }
}
  • Java 8부터는 지역변수가 final이 아니더라도, '사실상 final(effective final)'이면 사용 가능
  • 여기서 val은 이후 변경되지 않기 때문에 "사실상 final"로 간주됨

✅ 결과: 10


✅ 문제 6 – 지역 클래스 변수 변경

public class Main {
    public static void main(String[] args) {
        int val = 10;
        class Local {
            void modify() {
                val = 20;
            }
        }
        new Local().modify();
        System.out.println(val);
    }
}
int val = 10;
class Local {
    void modify() {
        val = 20;
    }
}
  • 이 코드는 지역 변수 val을 지역 클래스 내부에서 변경하려고 함
  • 지역 클래스(Local)는 바깥의 지역 변수(val)가 사실상 final일 때만 접근 가능하며,
    수정은 절대 불가

❌ 결과: 컴파일 오류

Local variable val defined in an enclosing scope must be final or effectively final


✅ 문제 7 – static 블록 + static 변수 선언 순서

public class Main {
    static {
        System.out.println("x = " + x);
    }
    static int x = 5;

    public static void main(String[] args) {
        System.out.println("main x = " + x);
    }
}
static {
    System.out.println("x = " + x);
}
static int x = 5;
  • static 블록은 클래스가 로드될 때 먼저 실행됨
  • static 변수는 순서대로 초기화됨
  • static 블록에서 x를 출력하는 시점에는 x가 아직 선언 전 → 기본값 사용

📌 기본값 규칙

  • int는 초기화 전에는 0이 기본값임

✅ 결과 출력:

x = 0
main x = 5

📘 정리 요약

문제정답설명 요약
1컴파일 오류지역 변수 선언 전에 자기 자신 참조 → 초기화 불가
2컴파일 오류지역 변수 선언 시 인스턴스 변수 가림 → this 필요
3컴파일 오류선언 중인 변수로 초기화 시도
4컴파일 오류같은 스코프에 i 중복 선언
510지역 클래스가 사실상 final인 val을 참조
6컴파일 오류지역 클래스 내부에서 지역 변수 val 수정 불가
7x = 0, main x = 5static 초기화 순서 주의

✅ 1. 자바에서 변수의 스코프(Scope)란?

변수 스코프란: "이 변수가 어디까지 살아서 쓸 수 있는가?" 를 정하는 범위

자바에서 스코프의 종류 요약

구분선언 위치스코프 범위예시
클래스 변수static 필드클래스 전체 (정적)static int x;
인스턴스 변수클래스의 필드인스턴스 전체 (비정적)int x;
지역 변수메서드 내부선언된 블록 내부int x = 3;
파라미터 변수메서드의 매개변수메서드 내void f(int x)
지역 클래스 변수지역 클래스 내부선언된 지역 클래스 내부class Local {}
블록 변수if, for 등 내부그 블록 내부만for (int i...)

✅ 2. final 변수란?

final int x = 10;
  • final이 붙은 변수는 "한 번만" 값을 가질 수 있어
  • 초기화 이후엔 값 변경 불가능
  • 변수에 대한 상수화(immutable) 의미

🔶 final이 쓰이는 곳 3가지

  1. 클래스 필드 final → 상수
  2. 메서드 파라미터 final → 전달받은 값 수정 금지
  3. 지역 변수 final → 메서드/블록 내의 값 불변

✅ 3. 지역 클래스(Local class)란?

void method() {
    class Local {
        void hello() {
            System.out.println("hi");
        }
    }
}
  • 클래스 안에서 또 다른 클래스를 정의하는 것
  • 지역 클래스는 자신을 감싸고 있는 메서드의 지역 변수에 접근할 수 있지만 제한 있음!

✅ 4. 지역 클래스와 지역 변수: 캡처의 조건

void method() {
    int a = 10;

    class Local {
        void run() {
            System.out.println(a); // ✅ 가능!
        }
    }
}

🔸 이때 a는 바깥 메서드의 지역 변수인데 어떻게 접근 가능할까?

✔ 자바 8 이상에서는 다음 조건이 충족되면 지역 변수 사용 가능:

  • 그 지역 변수는 사실상 final (effectively final)
  • 즉, 선언 후 값이 변경되지 않는다면 final로 간주함

🧪 예시 실험: 변수 변경해보면?

void method() {
    int a = 10;

    a = 20; // ❌

    class Local {
        void run() {
            System.out.println(a);
        }
    }
}

❌ 컴파일 에러:

Local variable a defined in an enclosing scope must be final or effectively final

👉 이유: a값이 변경되었기 때문에 final이 아님


✅ 5. 왜 final이어야 할까?

지역 클래스는 내부적으로 복사본을 갖는다
즉, 지역 변수 자체에 대한 참조를 저장하는 게 아니라, 복사값을 저장
그런데 지역 변수가 중간에 바뀌면? → 복사본과 실제값이 불일치 → 혼란

그래서 자바는 지역 클래스 내부에서 접근하는 지역 변수는 final만 허용


✅ 6. 지역 클래스의 변수 접근 범위 요약

변수 위치접근 가능 여부수정 가능 여부예시
클래스 필드Main.this.val
지역 변수 (final)final int x = 5;
지역 변수 (변경됨)int x = 5; x = 10;

🔍 시각적 정리 예시

public class Main {
    public static void main(String[] args) {
        int num = 10;      // 사실상 final
        int notFinal = 20;

        notFinal = 30;     // 변경 → notFinal은 더 이상 final 아님

        class Local {
            void run() {
                System.out.println(num);       // ✅ 가능
                // System.out.println(notFinal); // ❌ 에러!
            }
        }
    }
}

✅ 결론 요약 정리

키워드의미
final 지역 변수한 번만 초기화 가능, 이후 수정 불가
지역 클래스메서드 안에서 정의된 클래스
스코프선언된 블록 내에서만 유효
지역 클래스에서 접근 가능 변수final 혹은 사실상 final 변수만 접근 가능
접근 가능 이유자바는 지역 클래스가 감싸는 지역 변수의 "복사본"을 내부에 저장

0개의 댓글