연습 2(중간부터 스프링 빌더)

류한선·2025년 6월 20일

실기연습-2

목록 보기
14/95

좋습니다. 아래 코드를 한 줄 한 줄 디버깅하듯이 해설해드릴게요. 예제 값도 함께 넣어가며 변수의 변화까지 추적해서 완전히 해부합니다.


💡문제 코드 다시 보기 (체크)

public class Main {
    static int x = 5;

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

    public static int test(int x) {
        x += 5;
        change();<- 매개변수를 못받음
        return x;
    }

    public static void change() {
        x += 10;
    }
}
public static void change(int x) {
    x += 10;
} // 만약 받으려면 이렇게 바꿔야됨

🧠 예상 흐름 순서 & 변수 흐름

우리는 main()에서 시작하고, 그 안에서 test(x) 호출, 그리고 change() 호출, 마지막으로 출력됩니다.
변수 x는 클래스에 static int x = 5;와 main 내부의 int x = 10; 두 개가 존재합니다. 이름은 같지만 서로 다른 변수입니다.


🔍 1. static 변수 선언

static int x = 5;
  • 클래스 전체에서 공유되는 정적 변수 x를 선언하고 5로 초기화.

  • 여기서 xMain.x라고 불러도 됨.

  • 현재 상태:

    Main.x = 5

🔍 2. main 메서드 시작

public static void main(String[] args) {
  • 프로그램 시작점. 여기서부터 실행됩니다.

🔍 3. 지역 변수 x 선언

int x = 10;
  • main 함수 안에서 x라는 지역 변수를 선언하고 10으로 초기화.

  • 이 x는 static 변수 x를 가립니다 (shadowing).

  • 현재 상태:

    Main.x = 5 (static 변수)
    x = 10 (main 함수 안 지역 변수)

🔍 4. test(x) 호출

System.out.println(test(x));
  • main 함수 안의 지역 변수 x = 10을 test 함수에 인자로 넘김.
  • 즉, test(10)이 호출됩니다.

🔍 5. test 메서드 실행

public static int test(int x) {
  • test 메서드의 지역 변수 x는 main에서 넘어온 10입니다.
  • 즉, 현재 x = 10

x += 5;
  • x = 10 + 5 = 15

  • 현재 상태:

    test 함수 안의 x = 15

change();
  • change() 메서드를 호출합니다.

🔍 6. change 메서드 실행

public static void change() {
    x += 10;
}
  • 여기서의 x는 static 변수 Main.x입니다. (test 함수의 x 아님)
  • 기존 Main.x = 5, 여기에 10을 더함 → Main.x = 15

🔙 7. test 메서드 복귀

return x;
  • 여기서 리턴하는 xtest 메서드 안의 지역 변수 x = 15
  • 그래서 System.out.println(test(x));15 출력

🔍 8. 두 번째 출력

System.out.println(x);
  • 여기서 x는 main 함수의 지역 변수 → 여전히 10
  • 이유: test 안에서 x를 복사해서 넘겼기 때문에 원본은 바뀌지 않음

✅ 최종 출력

15  
10

✅ 정답: A번

15  
10

📌 요약 & 함정 포인트 정리

포인트설명
변수 shadowingmain의 지역 변수 xstatic x를 가림
인자 전달 방식자바는 기본형은 값 복사(pass by value) → 원본 x = 10은 변하지 않음
static 접근change()는 클래스 변수 x를 사용함 (Main.x)

좋습니다! 정보처리기사 실기나 자바 기본기 테스트에서 자주 나오는 배열 + 스코프(scope) 관련 함정 문제를 아래에 준비했습니다.


✅ 문제: 다음 Java 코드의 출력 결과를 구하시오.

public class Main {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        modify(arr);
        System.out.println(arr[0]);
    }

    public static void modify(int[] arr) {
        arr[0] = 10;
        arr = new int[]{4, 5, 6};
        arr[0] = 100;
    }
}

❓ 보기

A. 1
B. 10
C. 4
D. 100


📌 이 문제의 핵심 개념: 배열 + 참조 + 스코프(scope)

배열은 참조형(reference type)이기 때문에 함수에 넘기면 영향을 줄 수도 있고 안 줄 수도 있습니다. 그 차이가 시험 포인트입니다!


✅ 디버깅 & 해설 시작

🔸 1. main 메서드 시작

int[] arr = {1, 2, 3};
  • arr는 힙(Heap)에 만들어진 배열 [1, 2, 3]을 가리키는 참조 변수

  • 현재 상태:

    arr → [1, 2, 3]

modify(arr);
  • 배열 참조를 그대로 modify 함수에 넘김
  • 이때 **참조(주소)**가 복사되어 넘어감 → 둘 다 같은 배열을 가리킴

🔸 2. modify 함수 내부로 진입

arr[0] = 10;
  • 이건 원래 배열을 건드림 → 원래 배열의 첫 번째 값이 1 → 10으로 바뀜

  • 현재 상태:

    arr → [10, 2, 3] (main에서도 이렇게 바뀜)

arr = new int[]{4, 5, 6};
  • 여기서 중요한 전환 발생!
  • arr이 새 배열 [4, 5, 6]을 가리키도록 변경됨
  • 이건 modify 함수 안에서만 유효한 참조 변경 → main에서는 영향 없음

arr[0] = 100;
  • 이건 새로 생성한 배열의 첫 번째 요소 바꿈 →

    modify 함수의 arr → [100, 5, 6]
    main 함수의 arr → 여전히 [10, 2, 3]

🔸 3. 다시 main으로 돌아옴

System.out.println(arr[0]);
  • main의 arr은 여전히 [10, 2, 3]
  • 따라서 출력은 10

✅ 정답: B. 10


📌 요약 포인트 정리

개념설명
배열은 참조형함수에 배열을 넘기면 "주소"가 복사됨
함수 안에서 원소 변경원본 배열에 영향 있음
함수 안에서 arr = new ...참조 변수만 바뀜, 원본 배열과는 단절
스코프함수 안에서의 arr은 main의 arr과 같은 객체를 가리키지만, 새로 할당하면 따로 논다

🧠 시각화 도식

main:
   arr ─────┐
            ▼
         [1, 2, 3]modify() 호출
           ↓
     arr[0] = 10[10, 2, 3]
     arr = new int[]{4,5,6}[100, 5, 6] (함수 내 한정)
     ↳ main의 arr은 변하지 않음!

좋아요! 이어서 배열 + for-each문에 관련된 실기 스타일의 함정 문제를 드릴게요. 이번 문제는 배열 복사, for-each문, 값 전달 개념이 제대로 이해되지 않으면 100% 틀리게 만드는 문제입니다.


✅ for-each 문(체크)-값 복사

public class Main {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        
        for (int num : arr) {
            num = num * 2;
        }

        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
    }
}

❓ 보기

A. 2 4 6
B. 1 2 3
C. 0 0 0
D. 컴파일 에러


💡 이 문제의 핵심 개념

  • for-each 문은 배열 요소를 꺼내는 반복문이지만, 값을 복사해서 가져옵니다.
  • 배열에 실제로 반영되려면 arr[i] = ... 형식처럼 직접 접근해야 함
  • 따라서 num = num * 2arr의 값을 바꾸지 않음

✅ 디버깅 해설

int[] arr = {1, 2, 3};
  • 정수 배열 선언, 값은 [1, 2, 3]

for (int num : arr) {
    num = num * 2;
}
  • for-each 반복문
  • num은 arr 배열의 각 값을 "복사"해서 담는 지역 변수
  • 아래와 같은 흐름으로 작동함:
반복 순서num의 값num = num * 2 실행arr 내용
112 (num만 바뀜)[1, 2, 3]
224[1, 2, 3]
336[1, 2, 3]
  • arr은 그대로

for (int i = 0; i < arr.length; i++) {
    System.out.print(arr[i] + " ");
}
  • arr[0], arr[1], arr[2] 그대로 출력됨 → 1 2 3

✅ 정답: B. 1 2 3


🧠 왜 이런 문제가 중요한가?

구분설명
for-each문배열 값을 복사해 와서 변수에 담음 (원본 못 바꿈)
for문 + 인덱스배열 값 변경 가능 (arr[i] = ...)
실기 스타일"배열을 두 배로 바꾸는 코드"처럼 보이지만, 실제론 아무 영향 없음

✅ 잘못 고치면 벌어지는 실수

for (int num : arr) {
    num *= 2;
}

이걸 arr에 반영하려면 이렇게 써야 함:

for (int i = 0; i < arr.length; i++) {
    arr[i] *= 2;
}

✨ 정리 요약

개념설명
int num : arrarr[i] 값을 복사해서 num에 담음
num *= 2num만 바뀌고, arr은 안 바뀜
배열 변경하려면?arr[i] = arr[i] * 2;처럼 인덱스를 써야 함

좋아요! 이번에는 배열 + final + 메서드 전달 + 스코프 관련 함정을 섞은 실기 스타일 문제를 준비했어요.
이건 정말 많은 사람들이 직관과 실제 결과가 다르다는 이유로 틀리는 문제예요.


✅ 문제: 다음 Java 코드의 출력 결과를 구하시오.

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

        try {
            a[0] = 1;
            System.out.println("정상 실행");
        } catch (Exception e) {
            System.out.println("예외 발생");
        }
    }
}

❓ 보기

A. 정상 실행
B. 예외 발생
C. 아무 것도 출력되지 않음
D. 컴파일 에러


🔍 핵심 포인트 요약

  • int[] a = null; → a는 아무 배열도 가리키고 있지 않음
  • a[0] = 1;null을 참조해서 접근 시도NullPointerException 발생
  • try-catch로 감쌌기 때문에 프로그램은 죽지 않고 catch로 넘어감

✅ 디버깅 하듯 한 줄씩 완전 설명


int[] a = null;
  • 배열 참조 변수 a 선언

  • null을 대입 → 아무 배열도 가리키지 않음

  • 현재 상태:

    a → null

a[0] = 1;
  • a가 null인데 a[0]에 접근 시도
  • 👉 NullPointerException 발생
  • 자바에서는 null을 참조해서 필드나 배열 요소에 접근하면 반드시 예외 발생

try {
    ...
} catch (Exception e) {
    System.out.println("예외 발생");
}
  • 예외가 발생했기 때문에 catch 블록으로 이동
  • "예외 발생" 출력

✅ 정답: B. 예외 발생


🧠 핵심 개념 정리

내용설명
null 참조객체 또는 배열이 메모리에 없음. 접근 시 오류 발생
a[0]배열이 존재해야 접근 가능. null 상태에서 접근 → NullPointerException
try-catch예외 발생 시 프로그램 멈추지 않고 catch로 넘어감

💥 심화 응용 (실기에서 이렇게 꼽니다)

String[] arr = new String[3];
System.out.println(arr[0].length());
  • arr 자체는 null 아님 → 컴파일 에러 아님
  • 하지만 내부 요소 arr[0]은 아직 null → NullPointerException

🔹 실기에서는 배열은 만들어졌는데 요소는 null인 상황도 많이 냅니다.


✨ 정리 요약

상황발생 예외
배열 자체가 null → a[0] 접근NullPointerException
배열 요소가 null → arr[0].length()NullPointerException
배열 인덱스 초과 → arr[10]ArrayIndexOutOfBoundsException
배열 생성 없이 사용컴파일 에러 (int[] a; a[0] = 1;)

좋습니다!
이번에는 정보처리기사 실기 스타일로 자주 나오는 문자열 배열에서 null vs 빈 문자열("")의 차이를 문제로 내고, 각 줄을 완전 디버깅하듯 해설해드릴게요.
이건 정말 많이들 헷갈리는데, 실기 시험에서도 자주 꼬아서 냅니다.


✅ 문제: 다음 Java 코드의 출력 결과를 구하시오.

public class Main {
    public static void main(String[] args) {
        String[] arr = new String[3];
        arr[0] = "";
        arr[1] = null;
        arr[2] = "hi";

        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i].length());
        }
    }
}

❓ 보기

A.

0  
0  
2

B.

0  
Exception  

C.

Exception

D.

0  
Exception  
2

🔍 핵심 포인트: null""의 차이

표현의미설명
null참조 없음변수 자체가 아무 객체도 가리키지 않음
""빈 문자열길이가 0인 문자열 객체를 가리킴 (new String(""))

✅ 디버깅 해설


String[] arr = new String[3];
  • 문자열 배열 크기 3 생성
  • 각 요소는 자동으로 null로 초기화됨
arr = [null, null, null]

arr[0] = "";
  • 첫 번째 요소에 빈 문자열 대입
  • "".length()는 0 반환
arr = ["", null, null]

arr[1] = null;
  • 두 번째 요소에 명시적으로 null 대입 (사실상 변화 없음)
arr = ["", null, null]

arr[2] = "hi";
  • 세 번째 요소에 "hi" 대입
arr = ["", null, "hi"]

🔁 for 반복문 돌입


▸ i = 0 → arr[0] = ""

System.out.println(arr[0].length());
  • ""는 빈 문자열 → 길이 0
    ✅ 출력: 0

▸ i = 1 → arr[1] = null

System.out.println(arr[1].length());
  • ❗️여기서 문제 발생
  • null.length()는 객체가 없는데 메서드를 호출하므로 → NullPointerException 발생

👉 프로그램 강제 종료


✅ 정답: C. Exception

  • "0"은 출력되지만, 그 다음에 예외 발생하고 프로그램 중단됨0도 안 보이는 경우도 있음
  • 시험에서는 이런 경우 "Exception" 출력으로 간주됨

📌 확장 학습: .equals() 비교

표현안전 여부설명
"".equals(str)✅ 안전null이어도 에러 안남
str.equals("")❌ 위험str이 null이면 NPE 발생
String s = null;
System.out.println("".equals(s)); // true 또는 false → 안전
System.out.println(s.equals("")); // NullPointerException → 위험

✅ 정리 요약

표현의미.length()
null아무 객체도 참조 안 함❌ 예외 발생
""길이 0인 문자열✅ 0 반환

✨ 실전에서 나올 수 있는 형태

String[] arr = new String[3]; // 전부 null
for (String s : arr) {
    if (s.equals("")) { // ❌ 여기서 터짐
        ...
    }
}

이럴 땐 반드시 null 체크 먼저 해야 함:

if (s != null && s.equals("")) { // ✅ 안전한 코드

좋습니다!
이번에는 StringBuilder vs StringBuffer의 차이를 헷갈리게 만드는 문제를 드릴게요.
정보처리기사 실기에서 멀티스레드 + 문자열 처리, 또는 성능 비교 관련 문제에서 자주 나오는 함정입니다.


여기서 부터 스프링 빌더

✅ 문제: 다음 Java 코드의 출력 결과를 구하시오.

public class Main {
    public static void main(String[] args) {
        StringBuilder sb1 = new StringBuilder("A");
        StringBuffer sb2 = new StringBuffer("A");

        method(sb1);
        method(sb2);

        System.out.println(sb1);
        System.out.println(sb2);
    }

    public static void method(Object obj) {
        if (obj instanceof StringBuilder) {
            ((StringBuilder) obj).append("B");
        } else if (obj instanceof StringBuffer) {
            ((StringBuffer) obj).append("B");
        }
    }
}

❓ 보기

A.

A  
A

B.

AB  
AB

C.

AB  
A

D.

A  
AB

🔍 핵심 개념 비교: StringBuilder vs StringBuffer

구분StringBuilderStringBuffer
스레드 안전성❌ (비동기, non-thread-safe)✅ (동기화, thread-safe)
성능빠름느림
사용 목적단일 스레드 환경멀티 스레드 환경

❗하지만 이 문제에서는 스레드와 관련이 없습니다. → 같이 동작함


✅ 한 줄씩 완전 디버깅 해설


StringBuilder sb1 = new StringBuilder("A");
  • sb1 → "A"로 초기화
StringBuffer sb2 = new StringBuffer("A");
  • sb2 → "A"로 초기화

method(sb1);
  • obj = sb1 (instanceof StringBuilder → true)
  • ((StringBuilder) obj).append("B"); 실행됨
sb1 = "AB"

method(sb2);
  • obj = sb2 (instanceof StringBuffer → true)
  • ((StringBuffer) obj).append("B"); 실행됨
sb2 = "AB"

System.out.println(sb1); // "AB"
System.out.println(sb2); // "AB"

✅ 정답: B. AB AB


📌 요약 정리

요소설명
StringBuilder, StringBuffer둘 다 append()로 문자열 변경 가능
instanceof타입 체크해서 안전하게 캐스팅
스레드 여부여기선 단일 스레드이므로 둘 다 정상 작동

❗ 실기에서 꼬는 방식 예시

✅ 문제: 다음 중 StringBuffer와 StringBuilder의 차이에 대한 설명으로 옳은 것은?

  1. StringBuilder는 멀티 스레드 환경에서 안전하다.
  2. StringBuffer는 비동기 처리를 위해 만들어졌다.
  3. StringBuilder는 동기화를 제공하지 않는다.
  4. StringBuffer는 StringBuilder보다 빠르다.

정답: 3번


아주 좋습니다!
이번에는 실기에서 은근히 자주 꼬아서 나오는 **StringBuilder를 메서드에 넘겼을 때, 원본에 반영되는가?**에 대한 문제를 드릴게요.
이건 값 복사 vs 참조 전달, 그리고 .append()의 작동 방식까지 정확히 이해해야 맞출 수 있는 문제입니다.


✅ 문제: 다음 Java 코드의 출력 결과를 구하시오.

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Hi");
        modify(sb);
        System.out.println(sb);
    }

    public static void modify(StringBuilder sb) {
        sb.append(" there");
        sb = new StringBuilder("Oops");
        sb.append("!");
    }
}

❓ 보기

A. Hi there!
B. Oops!
C. Hi
D. Hi there


🔍 핵심 포인트

포인트설명
StringBuilder는 참조형객체를 참조하는 변수임
메서드에 넘기면?참조값이 복사되어 전달됨 (원본을 직접 바꿀 수 있음)
하지만 sb = new StringBuilder(...)이건 메서드 내 지역 변수만 바뀜. 원본과 단절

✅ 한 줄씩 완전 디버깅 해설


StringBuilder sb = new StringBuilder("Hi");
  • sb"Hi" 문자열을 갖는 StringBuilder 객체를 가리킴

  • 현재 상태:

    sb ─────┐
            ▼
        "Hi"

modify(sb);
  • sb참조값(주소) 가 메서드에 넘겨짐
  • 즉, modify 함수의 sb도 같은 "Hi" 객체를 가리킴

🔸 modify 함수 내부

sb.append(" there");
  • 현재 sb"Hi"를 가리키고 있음 → 거기에 " there" 붙임

  • 결과:

    sb (main과 공유 중) → "Hi there"

sb = new StringBuilder("Oops");
  • 여기서 중요한 포인트!
  • sb는 이제 "Oops"라는 새로운 StringBuilder 객체를 가리킴
  • 하지만 이건 modify 함수의 지역 변수 sb만 바뀐 것임
    → main의 sb는 여전히 "Hi there"

sb.append("!");
  • 지금은 "Oops" 객체에 "!"를 붙임 → "Oops!"
  • 그러나 이건 main과 무관함

🔙 main으로 돌아감

System.out.println(sb);
  • main의 sb는 "Hi"에서 "Hi there"로 바뀌었고,
  • "Oops"와는 전혀 관계 없음

✅ 정답: D. Hi there


📌 핵심 요약

구문영향 여부이유
sb.append(...)✅ 영향 있음원래 객체를 수정함
sb = new StringBuilder(...)❌ 영향 없음지역 변수만 바뀜 (원본 참조와 단절됨)

💡 시각화 요약

main:
   sb ─────┐
           ▼
       "Hi"append(" there")"Hi there"

modify:
   sb (같은 객체 참조)
   append(" there")"Hi there"
   sb = new StringBuilder("Oops") → 🔗 끊김 (main과 단절)
   append("!")"Oops!"

main:
   sb → 여전히 "Hi there"

0개의 댓글