스코프

류한선·2025년 6월 18일

실기연습-2

목록 보기
4/95

좋아! 스코프(Scope, 변수의 유효 범위)는 자바에서 매우 중요한 개념이고,
정보처리기사 실기에서 자주 함정 문제로 출제되는 부분이야.


🔍 스코프(Scope)란?

변수가 선언된 위치에 따라, 어디까지 그 변수를 사용할 수 있는지를 말해.


✅ 스코프의 종류 요약

종류설명예시 사용 가능 위치
클래스 스코프클래스 전체에서 접근 가능 (static 제외)모든 메서드 내부
메서드 스코프해당 메서드 내부에서만 사용 가능지역 변수 등
블록 스코프{} 블록 안에서 선언된 변수 (for, if 등)해당 블록 내부

✅ 실전 예제 1 – if 블록 안 변수 사용

public class Main {
    public static void main(String[] args) {
        if (true) {
            int a = 10;
            System.out.println(a);  // OK
        }

        System.out.println(a);  // ❌ 컴파일 오류 (a는 if블록 안에서만 유효)
    }
}

🧠 해설:

  • int a = 10;if 블록 내부 변수
  • System.out.println(a); (if 밖) → a는 이 위치에서 없음

✅ 실전 예제 2 – for 루프 변수 스코프

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            System.out.println(i);  // OK
        }

        System.out.println(i);  // ❌ 오류: i는 for문 안에서만 존재
    }
}

🔍 왜 오류?

  • int i = 0for문의 초기식에서 선언됨 → for문의 블록 안에서만 유효

✅ 실전 예제 3 – 변수 이름 충돌 (shadowing)

public class Main {
    static int x = 5;

    public static void main(String[] args) {
        int x = 10;

        System.out.println(x); // 출력값은?
    }
}

💡 출력은?

10

🧠 이유:

  • main 안에서 새로 선언된 int x = 10;
    클래스의 static int x = 5;가려버림(shadowing)

✅ 실전 예제 4 – 함수 파라미터와 로컬 변수 충돌

public class Main {
    public static void printSum(int a) {
        int b = 5;
        int a = 3; // ❌ 오류: 변수 a는 이미 파라미터로 존재
        System.out.println(a + b);
    }
}

❌ 컴파일 오류:

  • a는 이미 파라미터로 선언됨 → 같은 이름의 로컬 변수 선언 불가

✅ 실전 예제 5 – 블록 바깥에서 선언하면?

public class Main {
    public static void main(String[] args) {
        int sum = 0;

        for (int i = 0; i < 3; i++) {
            int temp = i * 2;
            sum += temp;
        }

        System.out.println(temp); // ❌ temp는 for문 안에서만 사용 가능
    }
}

✅ 실전 예제 6 – 같은 이름 재선언 허용?

public class Main {
    public static void main(String[] args) {
        int a = 5;
        {
            int a = 10; // ❌ 같은 블록 내에서 변수 이름 중복 선언 불가
        }
    }
}

❌ 오류 이유:

  • 같은 이름의 변수는 같은 메서드 스코프 내에서 재선언 불가

✅ 실전 예제 7 – 내부 블록은 바깥 변수 참조 가능

public class Main {
    public static void main(String[] args) {
        int outer = 100;

        {
            int inner = outer + 50; // OK: 외부 스코프 변수 사용 가능
            System.out.println(inner); // 150
        }

        System.out.println(inner); // ❌ inner는 블록 밖에서 사용 불가
    }
}

🧠 핵심 정리

사례변수 접근 가능 여부
바깥 변수 → 안쪽 블록가능 ✅
안쪽 변수 → 바깥 블록불가능 ❌
중첩 블록 안에서 이름 중복불가능 ❌ (같은 스코프 내)
메서드 파라미터와 중복불가능 ❌

좋아! 그럼 지금부터 위의 스코프 연습문제 10문제에 대해
하나하나 디버깅 수준으로 상세하게 해설해줄게.
각 줄에서 무슨 일이 일어나는지, 어떤 변수들이 어떤 범위에서 유효한지 모두 설명할게!


✅ 문제 1

public class Main {
    public static void main(String[] args) {
        int x = 5;
        {
            int x = 10;
            System.out.println(x);
        }
    }
}

🔍 해설:

  • int x = 5;main() 안에서 x라는 이름의 변수를 선언함 (메서드 스코프)

  • { int x = 10; ... }같은 스코프 내에 다시 x를 선언하려 함

    • 하지만 자바에서는 같은 메서드 스코프 내에서 변수 이름을 중복 선언할 수 없음.
    • 블록 안이라도 이전 x가 유효한 상태이므로, 컴파일 에러 발생!

❌ 결과: 컴파일 오류

❗ 이유: variable x is already defined in method main(String[])


✅ 문제 2

public class Main {
    public static void main(String[] args) {
        {
            int a = 3;
        }
        System.out.println(a);
    }
}

🔍 해설:

  • { int a = 3; } → a는 이 블록 안에서만 살아있는 블록 스코프 변수
  • System.out.println(a); → 이 줄은 a가 선언된 블록 바깥 → 접근 불가

❌ 결과: 컴파일 오류

❗ 이유: a cannot be resolved to a variable


✅ 문제 3

public class Main {
    static int value = 100;

    public static void main(String[] args) {
        int value = 50;
        System.out.println(value);
    }
}

🔍 해설:

  • 클래스 스코프에 static int value = 100;
  • 하지만 main() 안에서 int value = 50;을 새로 선언함
  • 이 경우, 로컬 변수가 클래스 변수와 이름이 겹쳐도 덮어쓰기 됨 → shadowing

✅ 출력: 50


✅ 문제 4

public class Main {
    public static void main(String[] args) {
        int x = 1;
        if (x < 10) {
            int y = 5;
        }
        System.out.println(y);
    }
}

🔍 해설:

  • int y = 5;if 블록 안에서 선언됨 → 블록 스코프
  • System.out.println(y);는 if 밖 → y 접근 불가

❌ 결과: 컴파일 오류

❗ 이유: y cannot be resolved to a variable


✅ 문제 5

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            int sum = i * 2;
            System.out.println(sum);
        }
        System.out.println(sum);
    }
}

🔍 해설:

  • int sum = ...for 블록 안에서 선언됨 → for문 안에서만 유효
  • 바깥에서 sum을 출력하려고 하므로 → 접근 불가

❌ 결과: 컴파일 오류

❗ 이유: sum cannot be resolved to a variable


✅ 문제 6

public class Main {
    public static void main(String[] args) {
        int a = 1;
        {
            int b = 2;
            {
                int c = 3;
                System.out.println(a + b + c);
            }
            System.out.println(c);
        }
    }
}

🔍 해설:

  • c는 가장 안쪽 블록에서만 유효함
  • System.out.println(c);c가 선언된 블록 바깥 → 접근 불가

❌ 결과: 컴파일 오류

❗ 오류 줄: System.out.println(c);
❗ 이유: c cannot be resolved to a variable


✅ 문제 7

public class Main {
    public static void print(int num) {
        int num = 10;
        System.out.println(num);
    }
}

🔍 해설:

  • 파라미터로 int num이 이미 선언되어 있음
  • 같은 메서드 안에서 같은 이름의 지역변수 재선언 불가

❌ 결과: 컴파일 오류

❗ 이유: variable num is already defined in method print(int)


✅ 문제 8

public class Main {
    static int x = 20;

    public static void test() {
        System.out.println(x);
    }

    public static void main(String[] args) {
        int x = 10;
        test();
    }
}

🔍 해설:

  • main 안의 x = 10은 지역 변수
  • test()는 자신의 지역 x가 없으므로 클래스의 static int x = 20 사용

✅ 출력: 20


✅ 문제 9

public class Main {
    public static void main(String[] args) {
        int a = 1;
        int a = 2;
        System.out.println(a);
    }
}

🔍 해설:

  • 같은 메서드 스코프 안에서 같은 이름의 변수 재선언은 불가

❌ 결과: 컴파일 오류

❗ 이유: variable a is already defined in method main(String[])


✅ 문제 10

public class Main {
    static int x = 10;

    public static void main(String[] args) {
        x = x + 5;  // 클래스 변수 x = 15
        {
            int x = 3;  // 이 x는 지역 변수, 클래스 x를 가림
            x = x + 1;  // 지역 변수 x = 4
        }
        System.out.println(x); // 출력되는 것은 클래스 변수 x = 15
    }
}

✅ 출력: 15

인스턴스와 상관없이 클래스가 소유하는 공유 변수-static 변수
final + static 진짜 "변경 불가한 상수"를 의미 (static final int A = 100;)


좋아! 이번엔 기본 개념을 아는 사람도 헷갈릴 수 있는
“꼬아낸” 자바 스코프 문제를 준비했어.
헷갈리는 이유는 shadowing, static/instance 섞기, 클래스 안 중첩, 메서드 내부 클래스 등으로 섞여 있어.


🧠 정보처리기사 실기 대비 - 고난이도 스코프 문제 7제

❗ 초보자는 당연히 틀리고, 중급자도 실수할 수 있게 일부러 헷갈리게 꼬았음
❗ 일부 문제는 컴파일 되지만, 일부는 "되긴 하는데 예상과 다른 결과"가 나옴


🔹 문제 1 – shadowing + static

public class Main {
    static int x = 10;

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

❓ 출력 결과는?


🔹 문제 2 – 메서드 내 지역 변수 vs 인스턴스 변수

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();
    }
}

❓ 실행되나? 된다면 출력값은?


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

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

❓ 컴파일 될까? 된다면 출력은?


🔹 문제 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);
        }
    }
}

❓ 컴파일 가능? 왜?


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

public class Main {
    public static void main(String[] args) {
        int val = 10;
        class Local {
            void print() {
                System.out.println(val);
            }
        }
        new Local().print();
    }
}

❓ 이 코드는 컴파일 되는가? 된다면 출력은?


🔹 문제 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);
    }
}

❓ 컴파일 되는가? 된다면 출력은?


🔹 문제 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);
    }
}

❓ 출력 순서와 출력 내용은?


좋아! 그럼 지금부터 위의 꼬아놓은 스코프 문제 7개를 하나씩,
각 줄에 어떤 일이 일어나는지 디버깅 수준으로 상세하게 해설해줄게.


✅ 문제 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 인스턴스 변수

int a = 1;
  • 인스턴스 변수 a 선언
int a = a + 1;
  • 지역 변수 a 선언하려는데 오른쪽 a는 지역 스코프의 a를 참조하려 함
  • 하지만 이 시점에는 지역 변수 a가 아직 존재하지 않음
  • 따라서 인스턴스 변수 a에 접근하려면 this.a를 써야 했음

❌ 결과: 컴파일 오류

variable a might not have been initialized


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

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 루프 안에서 변수 선언

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 – 지역 클래스 내부에서 변수 접근

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

✅ 결과: 10


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

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 변수 선언 순서

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 초기화 순서 주의

좋아, 그럼 문제 5, 6, 7번에 대해 "각 줄마다 디버깅 수준으로",
"왜 이 시점에서 그렇게 되는가?"를 시각적으로 해설해줄게.
자바의 지역 클래스(Local Class), 변수 캡처, 그리고 static 초기화 순서에 대한 심화 설명도 포함할게.


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

📜 코드:

public class Main {
    public static void main(String[] args) {
        int val = 10;
        class Local {
            void print() {
                System.out.println(val);
            }
        }
        new Local().print();
    }
}

🔍 줄별 해설

public class Main {
  • 클래스 선언 시작.
    public static void main(String[] args) {
  • main() 함수는 프로그램 실행의 시작점.
  • 여기 안에서 모든 로직이 진행됨.
        int val = 10;
  • val이라는 지역 변수 선언됨.
  • 이 변수는 main() 메서드 지역 스코프에 속함.
  • 🔸 자바 8 이상에서는 이 지역 변수가 사실상 final (effectively final) 이면 → 지역 클래스에서 참조 가능.
        class Local {
  • 메서드 안에 선언된 지역 클래스.
  • 이 클래스는 main()의 지역 스코프에만 존재함.
  • 지역 클래스는 바깥 메서드의 지역 변수들을 사용할 수 있음.
  • 하지만 값을 읽기만 가능하고 수정은 불가.
            void print() {
                System.out.println(val);
            }
  • val 사용 → 읽기만 함.
  • 여기서 val은 수정되지 않았으므로 "사실상 final" 상태.
  • 따라서 참조 가능.
        new Local().print();
  • Local 클래스의 객체를 생성하고 print() 호출.
  • 출력 결과는 val의 값인 10.

✅ 최종 출력:

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;
  • 지역 변수 val을 선언하고 10으로 초기화.
class Local {
    void modify() {
        val = 20;
    }
}

❌ 핵심 문제:

  • 지역 클래스(Local)는 바깥쪽의 지역 변수 val을 참조할 수 있지만,
  • 조건: 그 지역 변수는 "사실상 final"이어야 함
  • valmodify() 메서드에서 값을 변경하려고 함 → 더 이상 final이 아님
  • 그래서 자바는 컴파일 에러 발생
new Local().modify(); // 호출 안 됨 (컴파일도 안됨)

❌ 결과:

컴파일 에러:
Local variable val defined in an enclosing scope must be final or effectively final

🔎 요약 정리:

지역 변수 사용 조건읽기쓰기
사실상 final (val = 10)✅ 가능❌ 불가능
명시적 final (final val = 10)✅ 가능❌ 불가능

🔹 문제 7 – 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 초기화 순서 이해:

자바 클래스가 최초 로드될 때 다음 순서로 실행됨:

  1. static 변수들, static 블록이 코드 순서대로 실행됨
  2. 이때 아직 선언되지 않은 static 변수는 기본값(default) 으로 존재함

🔍 줄별 해설

static {
    System.out.println("x = " + x);
}
  • static 블록: 클래스가 로딩될 때 실행됨
  • x는 아직 초기화 전 → 자동으로 int의 기본값인 0

✔ 출력:

x = 0
static int x = 5;
  • 이제 x가 5로 초기화됨
System.out.println("main x = " + x);
  • x는 5이므로 출력:
main x = 5

✅ 최종 출력:

x = 0
main x = 5

🧠 요약 포인트

주제개념 요약
지역 클래스 변수 접근메서드 안의 지역 변수는 사실상 final일 때만 접근 가능 (Java 8+)
지역 클래스 변수 수정절대 불가능 – 읽기만 가능
static 초기화 순서선언 순서대로 초기화됨. static 블록은 위에 있으면 변수 초기화 전 실행됨

좋아, 방금 제시한 이 코드를 디버깅 하듯 한 줄씩 해설해볼게.
초보자가 가장 많이 틀리는 "지역 변수와 final, 지역 클래스(Local Class)" 스코프 문제야.


🔍 전체 코드

public class Main {
    public static void main(String[] args) {
        int x = 5;
        int y = 10;

        x = 7;

        class Local {
            void print() {
                System.out.println(x + y);
            }
        }

        new Local().print();
    }
}

🧠 먼저 요약 정답부터:

❌ 이 코드는 컴파일 오류 발생함

오류 메시지는 다음과 같아:

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

🔍 이제 디버깅 하듯 한 줄씩 천천히 해설할게:


🔹 public class Main {

  • 클래스 선언
  • 이름은 Main
  • 이 클래스는 main() 메서드 하나를 가짐

🔹 public static void main(String[] args) {

  • 자바 프로그램의 시작점
  • main() 안에서 모든 코드가 실행됨

🔹 int x = 5;

  • xmain()지역 변수
  • 현재 값은 5
  • 지금은 "사실상 final" 상태

🔹 int y = 10;

  • y도 지역 변수
  • 지금도 값을 한 번만 대입했기 때문에 사실상 final

🔹 x = 7;

  • 중요한 줄!

📌 이 줄 때문에 x는 더 이상 "사실상 final"이 아님
→ 왜냐면, 초기값 이후에 다시 대입되었기 때문


🔹 class Local { ... }

  • 지역 클래스 Local 선언

  • 지역 클래스는 감싸고 있는 main()의 지역 변수에 접근할 수 있음

  • 단, 접근 가능한 조건:

    • 그 지역 변수는 final 또는 사실상 final 일 것

🔹 void print() { System.out.println(x + y); }

  • print() 메서드는 xy를 더해서 출력하려고 함

  • 여기서 문제 발생:

    • x수정되었기 때문에 → ❌ 접근 불가 (컴파일 에러)
    • y는 값이 변경되지 않았기 때문에 → ✅ 접근 가능

🔹 new Local().print();

  • Local 객체를 만들어서 print() 호출 시도

하지만 앞에서 x는 접근 자체가 불가능하므로 컴파일 에러 발생


✅ 요약: 왜 에러가 나는가?

  • 지역 클래스는 감싸고 있는 지역 변수들을 사용할 수 있지만
  • "값을 변경하지 않은 경우", 즉 사실상 final인 경우에만 허용

📌 그래서 이 코드에서 변수 상태는?

변수변경 여부사실상 final?지역 클래스 접근 가능?
x변경됨❌ 접근 불가
y변경 안됨✅ 접근 가능

💡 해결 방법은?

방법 1: x를 final로 만들기

final int x = 5; // 값 변경 금지

방법 2: x = 7; 줄을 제거해서 값 안 바꾸게 하기

// x = 7; 주석 처리 또는 삭제

이렇게 하면 x가 사실상 final이 되어 정상 작동함


🔚 최종 출력 결과 (수정했을 경우)

int x = 5; // 또는 final int x = 5;
int y = 10;

// x = 7; 없애기

System.out.println(x + y); // 5 + 10 = 15
출력 결과: 15

0개의 댓글