정보처리기사

[정보처리기사 실기 오답노트] - Java

sson-coding 2025. 11. 10. 11:38

2024-3-1

다음 JAVA 로 구현된 프로그램을 분석하여 실행 결과를 쓰시오.

public class Main {
    static String[] x = new String[3];

    static void func(String[] x, int y) {
        for (int i = 1; i < y; i++) {
            if (x[i - 1].equals(x[i])) {
                System.out.print("O");
            } else {
                System.out.print("N");
            }
        }

        for (String z : x) {
            System.out.print(z);
        }
    }

    public static void main(String[] args) {
        x[0] = "A";
        x[1] = "A";
        x[2] = new String("A");
        func(x, 3);
    }
}
  • 내 답 : NNAAA
  • 정답 : OOAAA
  • 틀린 이유 : 같은데 다르다고 생각해서 N 으로 혼동

핵심 개념

  • equals() : 내용 비교
  • == : 참조 비교

풀이

  1. main() 실행 시
  2. x[0] = "A"; // 문자열 리터럴 "A" x[1] = "A"; // 같은 리터럴이므로 같은 객체 참조 x[2] = new String("A"); // 새 객체 생성 (주소 다름)
  3. func(x, 3) 호출
    • 첫 번째 for문:
      • i = 1 → x[0].equals(x[1]) → "A".equals("A") → true → 'O' 출력
      • i = 2 → x[1].equals(x[2]) → "A".equals(new String("A")) → 내용이 같으므로 true → 'O' 출력
  4. 두 번째 for문(for(String z : x))
    • 각각 "A", "A", "A" 출력 → "AAA"
  5. 최종 출력:
  6. OOAAA

2024-3-17

public class ExceptionHandling {
  public static void main(String[] args) {
      int sum = 0;
      try {
          func();
      } catch (NullPointerException e) {
          sum = sum + 1;
      } catch (Exception e) {
          sum = sum + 10;
      } finally {
          sum = sum + 100;
      }
      System.out.print(sum);
  }
 
  static void func() throws Exception {
      throw new NullPointerException(); 
  }
}
  • 내 답 : 110
  • 정답 : 101

핵심 개념

  • throw : 강제로 예외를 발생시키는 키워드
  • NullPointerException : Null 을 가진 객체를 참조하는 경우 사용하는 예외 객체
  • catch 순서: 구체적인 예외 → 일반적인 예외
  • finally: 예외 발생 여부와 무관하게 항상 실행
  • 예외 매칭: 발생한 예외와 일치하는 첫 번째 catch만 실행

풀이

단계 코드 sum 값

초기화 int sum = 0 0
try func() 호출 → NPE 발생 0
catch(NPE) sum = sum + 1 1
catch(Exception) 실행 안 됨 1
finally sum = sum + 100 101
출력 System.out.print(sum) 101

2024-03-18

class Printer{
      void print(Integer a){
        System.out.print("A" + a);
      }
      void print(Object a){
        System.out.print("B" + a);
      } 
      void print(Number a){
        System.out.print("C" + a);
      }
}
public class Main {
	public static void main(String[] args) {
      new Collection<>(0).print();
  }
  
  public static class Collection<T>{
    T value;
 
    public Collection(T t){
        value = t;
    }
 
    public void print(){
       new Printer().print(value);
    }
 }
}
  • 내 답 : A
  • 정답 : B0

핵심 개념

  • 제네릭
    • 컴파일 시점에 제네릭 타입 정보가 소거됨
    • T 는 컴파일 이후 Object 로 변환됨

풀이과정

  1. main→ new Collection<>(0).print(); → Collection<Integer> 타입 생성
  2. 제네릭 타입 소거 : 컴파일 후
  3. public static class Collection { Object value; // T → Object로 변환! public void print() { new Printer().print(value); // value는 Object 타입! } }
  4. 메서드 오버로딩 선택
    • value 의 타입은 Object
    • void print(Object a) 선택
  5. 출력
    • 처음에 전달한 수 가 0 이므로 B0 출력

2024-2-1

class Main {
    public static void main(String[] args) {
        String str = "ITISTESTSTRING";
        String[] result = str.split("T");
        System.out.print(result[3]);
    }
}
  • 내 답 : ST
  • 정답 : S

핵심 개념

  • String.split()
    • 문자열을 지정한 구분자 기준으로 나누어 배열로 반환함
    • 지정한 구분자 앞에서 자름

풀이

# split 전
String str = "ITISTESTSTRING";

# split 
result = ["I", "IS", "ES", "S", "RING"]


2024-2-8

class Main {
    public static void main(String[] args) {
        String str = "abacabcd";
        boolean[] seen = new boolean[256];
        System.out.print(calculFn(str, str.length()-1, seen));
    }
 
    public static String calculFn(String str, int index, boolean[] seen) {
        if(index < 0) return "";
        char c = str.charAt(index);
        String result = calculFn(str, index-1, seen);
        if(!seen[c]) {
            seen[c] = true;
            return c + result;
        }
        return result;
    }
}
  • 내 답 : dcbacaba
  • 정답 : dcba

핵심 개념

  • boolean[] seen
    • 문자가 등장했는지 여부를 seen[문자코드] 로 기록
  • charAt(index)
    • 0 부터 시작한다.
    • index 에 나오는 문자를 반환

풀이

  1. 초기값
String str = "abacabcd";
boolean[] seen = new boolean[256];
System.out.print(calculFn(str, str.length()-1, seen));
  • str = "abacabcd"
  • index = 7 (마지막 문자 d)
  • seen 배열은 전부 false로 초기화됨
  1. 재귀 호출
  • 함수가 index를 7 → 0까지 줄이면서 순서대로 실행됨.

index 문자 이미 본 적 있음? seen 등록 결과 누적

7 d seen['d']=true "d"
6 c seen['c']=true "cd"
5 b seen['b']=true "bcd"
4 a seen['a']=true "abcd"
3 c 그대로 유지 "abcd"
2 a 그대로 유지 "abcd"
1 b 그대로 유지 "abcd"
0 a 그대로 유지 "abcd"
  1. 최종 결과
  • calculFn 은 뒤에서부터 처리함
  • 문자열의 마지막 등장 순서 기준으로 중복 제거된 결과를 출력
  • dcba

2024-1-5

class Connection {
 
    private static Connection _inst = null;
    private int count = 0;
    
    static public Connection get() {
        if(_inst == null) {
            _inst = new Connection();
            return _inst;
        }
        return _inst;
    }
    
    public void count() {
         count++; 
    }
    
    public int getCount() {
         return count; 
    }
}
 
 
public class main {  
 
    public static void main(String[] args) {
 
        Connection conn1 = Connection.get();
        conn1.count();
 
        Connection conn2 = Connection.get();
        conn2.count();
 
        Connection conn3 = Connection.get();
        conn3.count();
        
        conn1.count();
        System.out.print(conn1.getCount());
    }
 
}
  • 내 답 : 2
  • 정답 : 4

핵심 개념

메모리 영역 저장되는 것 특징

Method Area (메서드 영역) 클래스 정보, static 변수, 메서드 코드 프로그램 시작 시 로드, 클래스 전체가 공유
Heap (힙 영역) new로 생성된 객체 런타임에 동적으로 생성, GC에 의해 해제
Stack (스택 영역) 메서드의 지역변수, 매개변수, 참조변수 메서드 호출 시 생성, 종료 시 자동 제거

풀이

  1. public static void main(String[] args) {
    • JVM이 main() 메서드를 호출 → main 스택 프레임이 생성됨.
    • 이 시점에서 아직 Connection 클래스의 객체는 없음.
  2. Connection 클래스 로딩
    • Connection conn1 = Connection.get(); 구문이 실행되면 JVM은 Connection 클래스를 처음으로 사용하기 때문에 클래스 정보를 메서드 영역(Method Area) 에 로드한다.
    • 이 시점에 메서드 영역에는 다음 정보가 올라간다.
      • 정적 변수 _inst (초기값 null)
      • 정적 메서드 get()
      • 인스턴스 메서드 count()와 getCount()
    • 아직 객체는 만들어지지 않았고, 단지 클래스 정의만 메모리에 존재한다.
  3. 첫 번째 Connection.get() 호출
    • main() 메서드의 스택 프레임(Stack Frame) 안에 지역변수 conn1이 생성된다. 아직 값은 null 상태이다.
    • get() 메서드를 호출하면 새로운 스택 프레임이 만들어지고, 메서드 내부에서 _inst == null 조건이 참이므로 new Connection()이 실행된다.
    • new Connection()이 실행되면 힙(Heap) 영역에 Connection 객체가 새로 생성되고, 그 안의 필드 count가 0으로 초기화된다.
    • 그 다음 _inst는 이 힙 객체의 주소를 저장하게 된다.
    • get()이 _inst를 반환하므로 conn1이 그 주소를 받아 같은 객체를 가리킨다.
    • 즉, 메서드 영역에는 _inst, 힙에는 Connection 객체, 스택에는 conn1이 있고, 셋이 연결된 상태가 된다.
  4. conn1.count() 실행
    • conn1이 가리키는 힙 객체의 count 필드가 0 → 1로 증가한다.
    • 스택에는 아무 변화가 없고, 힙 영역의 객체 내부 값만 바뀐다.
  5. 두 번째 호출 Connection conn2 = Connection.get();
    • 스택에 새로운 지역변수 conn2가 생긴다.
    • 이번에 get()을 호출하면 _inst가 이미 null이 아니므로 새로운 객체를 만들지 않고 기존 _inst를 그대로 반환한다.
    • 따라서 conn2도 conn1과 같은 힙 객체의 주소를 갖게 된다.
  6. conn2.count() 실행
    • 같은 힙 객체의 count가 1 → 2로 증가한다.
  7. 세 번째 호출 Connection conn3 = Connection.get();
    • 스택에 지역변수 conn3가 생긴다.
    • _inst는 여전히 기존 객체를 가리키고 있으므로, conn3 역시 같은 힙 객체를 참조하게 된다.
  8. conn3.count() 실행
    • 동일한 객체의 count가 2 → 3으로 증가한다.
  9. 다시 conn1.count() 실행
    • conn1, conn2, conn3는 모두 같은 객체를 가리키므로 이 호출로 count가 3 → 4로 증가한다.
  10. 최종 출력
    • System.out.print(conn1.getCount());가 호출되면 conn1이 참조하는 힙 객체의 count 값을 반환한다. 현재 값은 4이므로 화면에 4가 출력된다.

2023-3-1

다음 자바 코드를 실행할 경우 에러가 발생이 된다. 에러가 발생하는 라인을 작성하시오.

class Person {
    private String name;
    public Person(String val) {
        name = val;
    }
    public static String get() {
        return name;
    }
    public void print() {
        System.out.println(name);
    }
}

public class main {
    public static void main(String[] args) {
        Person obj = new Person("Kim");
        obj.print();
    }
}

답 : return name;

핵심개념

  • static 메서드
    • 클래스 이름으로 호출되며, 객체 생성 없이 사용 가능
    • 인스턴스 변수에 접근할 수 없음

풀이

  • name 은 인스턴스 변수이므로 static 메서드 내부에서 사용할 수 없음

2023-3-14

class P {
    public int calc(int n) {
        if (n <= 1) return n;
        return calc(n - 1) + calc(n - 2);
    }
}

class C extends P {
    public int calc(int n) {
        if (n <= 1) return n;
        return calc(n - 1) + calc(n - 3);
    }
}

public class Test {
    public static void main(String[] args) {
        P obj = new C();
        System.out.print(obj.calc(7));
    }
}

  • 정답 : 2

풀이

  1. main()
P obj = new C();
obj.calc(7);
  • obj 의 실제 타입은 C → C 의 calc() 가 실행
  1. 계산
calc(7) = calc(6) + calc(4)
calc(6) = calc(5) + calc(3)
calc(5) = calc(4) + calc(2)
calc(4) = calc(3) + calc(1)
calc(3) = calc(2) + calc(0)
calc(2) = calc(1) + calc(-1)

calc(1) = 1
calc(0) = 0
calc(-1) = -1  (n<=1이므로 -1 반환)
calc(2) = 1 + (-1) = 0
calc(3) = 0 + 0 = 0
calc(4) = 0 + 1 = 1
calc(5) = 1 + 0 = 1
calc(6) = 1 + 0 = 1
calc(7) = 1 + 1 = 2

2021-3-17

public class Test {
    public static void main(String[] args) {
        int w = 3, x = 4, y = 3, z = 5;
        if ((w == 2 || w == y) && (!(y >= z)) && (1 == x ^ y != z)) {
            w = x + y;
            if (7 == w || y != w)
                System.out.println(w);
            else
                System.out.println(x);
        } else {
            w = y + z;
            if (7 == y ^ z != w)
                System.out.println(w);
            else
                System.out.println(z);
        }
    }
}

  • 정답 : 7

핵심개념

  • XOR(^)
    • 두 논리 값이 다를 때 true

풀이

  1. 초기값 → w=3, x=4, y=3, z=5
  2. if 조건식 평가
  • (w == 2 || w == y) → (3 == 2 || 3 == 3) → true
  • (!(y >= z)) → !(3 >= 5) → !(false) → true
  • (1 == x ^ y != z) → (false ^ true) → true
  • → 전체 조건: true && true && true → true, 따라서 if 블록 실행
  1. if 블록 내부 실행
  • w = x + y → w = 4 + 3 = 7
  • 조건 (7 == w || y != w) → (7 == 7 || 3 != 7) → true → System.out.println(w); 실행

2020-4*5-7

다음 빈 칸에 알맞은 답을 쓰시오. (10을 2진수로 변환)

public class Test {
    public static void main(String[] args) {
        int a[] = new int[8];
        int i = 0, n = 10;
        while (①) {
            a[i++] = ②;
            n /= 2;
        }
        for (i = 7; i >= 0; i--)
            System.out.printf("%d", a[i]);
    }
}

  • 답 : n>0 , n%2

풀이

  1. 반복 조건 판단
    • n이 0이 되면 더 이상 나눌 수 없으므로 ① n > 0 (또는 n != 0)가 맞다.
  2. 현재 비트 계산
    • 현재 n을 2로 나눈 나머지가 이번 단계의 2진수 비트이므로 ② n % 2.
    • a[i++]에 저장하면서 인덱스 i가 1 증가한다. (하위 비트부터 a[0], a[1]...에 쌓임)
  3. 단계별 실행 추적 (초기: i=0, n=10, a는 전부 0)
    • 1회전: a[0] = 10 % 2 = 0, i=1, n = 10 / 2 = 5
    • 2회전: a[1] = 5 % 2 = 1, i=2, n = 5 / 2 = 2
    • 3회전: a[2] = 2 % 2 = 0, i=3, n = 2 / 2 = 1
    • 4회전: a[3] = 1 % 2 = 1, i=4, n = 1 / 2 = 0 → while 종료
    • 종료 시 배열(앞 4칸만 채워짐): a = [0,1,0,1,0,0,0,0] (나머지 미사용 칸은 0 유지)

2025-1-5

public class Main {
    public static void main(String[] args) {
        int a = 5, b = 0;

        try {
            System.out.print(a / b);
        } catch (ArithmeticException e) {
            System.out.print("출력1");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.print("출력2");
        } catch (NumberFormatException e) {
            System.out.print("출력3");
        } catch (Exception e) {
            System.out.print("출력4");
        } finally {
            System.out.print("출력5");
        }
    }
}

  • 정답 : 출력1출력5

핵심개념

  • ArithmeticException
    • 0으로 나누기시 발생하는 예외
  • ArrayIndexOutOfBoundsException
    • 배열 인덱스 범위를 벗어나는 예외
  • NumberFormatException
    • 문자열 → 숫자 변환 실패 예외

풀이

  1. int a = 5, b = 0;
    • b가 0이므로 a / b 수행 시 ArithmeticException (산술 예외) 발생.
  2. 예외 발생 후 catch (ArithmeticException e) 블록 실행
    • "출력1" 출력.
  3. finally 블록은 항상 실행됨
    • "출력5" 출력.

2025-1-13

class parent {
    static int total = 0;
    int v = 1;
    parent() {
        total += (++v);
        show();
    }
    public void show() {
        total += total;
    }
}

class child extends parent {
    int v = 10;
    child() {
        v += 2;
        total += (v++);
        show();
    }
    @Override 
    public void show() {
        total += total * 2;
    }
}

class Main {
    public static void main(String[] args) {
        new child();
        System.out.println(parent.total);
    }
}
  • 정답 : 13

풀이

  1. new Child() : 객체 생성
    • parent() → total += (++v)
      • 부모의 v는 1 → ++v로 2
      • total = 0 + 2 = 2
    • 부모 생성자 안의 show() 호출
      • 하지만 자식이 오버라이드한 show() 가 실행된다.
      • total = 2 + (2 * 2) = 6
  2. 부모 생성자 종료 후, 자식 생성자 실행
    • 현재 자식의 v = 10
    • v += 2; → v = 12
    • total += (v++); → total = 6 + 12 = 18, 이후 v = 13
    • show() 호출 → 자식 show 실행
    • total = 18 + (18 * 2) = 54
  3. v += 2; total += (v++); show();
  4. 최종 결과

단계 실행 위치 total 변화 v(부모) v(자식) 설명

초기   0 1 10  
1 parent() → ++v 2 2 10 부모 v 증가
2 show()(자식) 6 2 10 오버라이딩 호출
3 v += 2 6 2 12 자식 생성자 실행
4 total += (v++) 18 2 13 후위 증가
5 show()(자식) 54 2 13 total + total*2
출력   54    

2025-2-5

public class Main {
    public static void change(String[] data, String s){
        data[0] = s;
        s = "Z";
    }

    public static void main(String[] args) {
        String data[] = { "A" };
        String s = "B";
        
        change(data, s);
        System.out.print(data[0] + s);
    }
}

  • 정답 : BB

풀이

  1. main
    • data : 배열 객체의 주소를 가짐
    • s : 문자열 B
  2. change(data,s)
    • 매개변수 전달
      • data : 배열의 주소가 복사되어 전달됨
      • s : B 값이 복사되어 전달됨
  3. change() 내부 동작
    • data[0] = s
      • 기존 : data[0] = A
      • 변경 : data[0] = B
    • s = “Z”
      • change 메서드 내부의 지역 변수 s 만 바뀜
      • main 의 s 는 B
  4. 출력
    • System.out.print(data[0] + s);
    • “B”+”B” = “BB”

2025-2-9

public class Main {
 
    static interface F {
        int apply(int x) throws Exception;
    }
 
    public static int run(F f) {
        try {
            return f.apply(3);
        } catch (Exception e) {
            return 7;
        }
    }
 
    public static void main(String[] args) {
 
        F f = (x) -> {
            if (x > 2) {
                throw new Exception();
            }
            return x * 2;
        };
 
        System.out.print(run(f) + run((int n) -> n + 9));
    }
}
  • 정답 : 19

풀이

  1. main() 시작
    • f는 입력값이 2보다 크면 예외를 던지는 함수
  2. run(f) 호출
    • f.apply(3) 실행
      • x = 3, x > 2 이므로 throw new Exception() 발생
      • 예외 발생 시 catch (Exception e) 블록 실행 → return 7;
    • 결과: run(f) → 7
  3. run((int n) → n+9) 호출
    • apply(3) → 3 + 9 = 12
    • 예외 없음 → catch 실행되지 않음
    • 결과: run((int n) -> n + 9) → 12
  4. 결과
    • 7 + 12 = 19

2025-2-10

public class Main{

    public static class Parent {
        public int x(int i) { return i + 2; }
        public static String id() { return "P"; }
    }

    public static class Child extends Parent {
        public int x(int i) { return i + 3; }  
        public String x(String s) { return s + "R"; }
        public static String id() { return "C"; }     
    }

    public static void main(String[] args) {
        Parent ref = new Child();
        System.out.println(ref.x(2) + ref.id());
    }
}

  • 정답 : 5P

핵심개념

개념 설명

오버라이딩(Overriding) 부모 클래스의 메서드를 자식이 재정의런타임(동적 바인딩) 시 실제 객체 기준으로 호출됨
오버로딩(Overloading) 이름은 같지만 매개변수 타입/개수가 다름
static 메서드 클래스명 기준으로 호출, 참조 변수 타입(컴파일타임) 기준으로 결정됨 (정적 바인딩)
참조 변수 vs 실제 객체 Parent ref = new Child(); → ref는 Parent 타입, 객체는 Child

풀이

  1. Parent ref = new Child();
    • ref의 컴파일 타입은 Parent, 실제 객체 타입은 Child.
  2. ref.x(2)
    • x(int i) 메서드는 오버라이딩 되어 있음.
    • 실행 시 실제 객체(Child)의 메서드가 호출됨 → 2 + 3 = 5.
  3. ref.id()
    • id()는 static 메서드이므로 오버라이딩되지 않음.
    • 참조 변수 타입(Parent) 기준으로 호출됨 → "P" 반환.
  4. 출력
    • 5 + "P"
    • 5P

2025-2-15

public class Main{
    public static class BO {
        public int v;
        public BO(int v) {
            this.v = v;
        }
    }
    public static void main(String[] args) {
        BO a = new BO(1);
        BO b = new BO(2);
        BO c = new BO(3);
        BO[] arr = {a, b, c};
        BO t = arr[0];
        arr[0] = arr[2];
        arr[2] = t;
        arr[1].v = arr[0].v;
        System.out.println(a.v + "a" + b.v + "b" + c.v);
    }
}
  • 정답 : 1a3b3

풀이

  1. 객체 생성
    • a.v = 1, b.v = 2, c.v = 3
  2. 배열 초기화인덱스 값 (참조)
    arr[0] → a (v=1)
    arr[1] → b (v=2)
    arr[2] → c (v=3)
  3. 교환인덱스 값 (참조)
    arr[0] → c (v=3)
    arr[1] → b (v=2)
    arr[2] → a (v=1)
  4. BO t = arr[0]; // t → a arr[0] = arr[2]; // arr[0] → c arr[2] = t; // arr[2] → a
  5. 값 변경
    • arr[1].v = arr[0].v;
    • arr[1] → b, arr[0] → c
    • 따라서 b.v = c.v = 3
  6. 출력
    • a.v = 1
    • b.v = 3
    • c.v = 3