정보처리기사 실기 개념정리 목차

Java — 바인딩 규칙이 문제의 8할이다

Java 문항은 매회 2~4개, 그리고 거의 전부가 "어느 메서드/필드가 선택되는가" 하나로 수렴한다. 오버라이딩·오버로딩·하이딩·섀도잉의 4규칙 표를 체화하면 절반은 끝난다. 이 편의 코드는 전부 2024~2026년 기출 복원이며 javac로 실행 검증했다.


1. 4규칙 표 — 무엇이 언제 결정되는가

대상결정 시점기준이름
인스턴스 메서드 (재정의)런타임실제 객체 타입오버라이딩 (동적 바인딩)
메서드 시그니처 선택컴파일 타임참조(선언) 타입에 보이는 것오버로딩 (정적 선택)
static 메서드컴파일 타임참조 타입하이딩 (메서드 숨김)
필드컴파일 타임참조 타입섀도잉 (필드 은닉)

한 줄 요약: 인스턴스 메서드만 실제 객체를 따라가고, 나머지 전부는 참조 타입을 따른다.

1.1 하이딩+오버라이딩 복합 (2025-2 기출 → 5P)

class P {
    static String print() { return "P"; }
    int sum(int a) { return a + 1; }
}
class C extends P {
    static String print() { return "C"; }
    int sum(int a) { return a + 2; }
}
P tmp = new C();
System.out.println(tmp.sum(3) + tmp.print());
/* sum: 인스턴스 메서드 → C의 것 → 5
   print: static → 참조 타입 P의 것 → "P"  ⇒ 5P */

1.2 필드 섀도잉 (2024-3 기출 → 52)

class B { int x = 3;  int getX() { return x * 2; } }
class A extends B { int x = 7;  int getX() { return x * 3; } }

B b1 = new A();
A b2 = new A();
System.out.print(b1.getX() + b1.x + b2.getX() + b2.x);
/* b1.getX() → A의 것 21 (메서드=동적)
   b1.x      → B의 3   (필드=참조 타입!)
   b2 → 21 + 7          ⇒ 21+3+21+7 = 52 */

함정 — 필드는 오버라이드되지 않는다. 부모/자식이 같은 이름의 필드를 각각 가질 뿐, 어느 것이 보이느냐는 참조 타입이 정한다.

1.3 오버로딩은 컴파일 타임 — 2026-1회 최다 오답 문항

class A {
    String f(Object x) { return "1"; }
    String g() { return f("a"); }      // ← 컴파일 시 A에 보이는 f(Object)로 확정
}
class B extends A {
    String f(Object x) { return "2"; } // 오버라이드 (런타임에 이것이 실행됨)
    String f(String x) { return "3"; } // 새 오버로드 — 호출 후보조차 아니다
}
A a = new B();
System.out.println(a.g());   /* → 2  ("3"이 대표 오답) */

2단계로 갈라 읽어라 — ① 컴파일: 선언 타입(A)의 후보 중 시그니처 확정(f(Object)). ② 런타임: 그 시그니처를 실제 객체(B)가 재정의했으면 그쪽 실행. B의 f(String)은 A에 없던 신규 오버로드라 ①에서 이미 배제된다.

1.4 제네릭 소거 + 오버로딩 (2024-3 기출 → B0)

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); }
}
/* Collection<T>의 value(타입 변수 T, 상한 없음)를 print(value) 하면?
   → T는 소거(erasure) 후 Object — print(Object) 선택 ⇒ B0 */

런타임에 값이 Integer(0)라는 사실은 아무 영향이 없다. 상한이 T extends Number였다면 C0가 됐을 것 — 오버로드 선택은 철저히 컴파일 시점의 정적 타입 게임이다.


2. == vs equals — 참조 비교와 내용 비교

/* 2024-2 기출 → NNN */
int a[] = {1,2,3,4};  int b[] = {1,2,3,4};  int c[] = {1,2,3};
check(a, b);   // a == b : 내용 같아도 다른 객체 → N
/* 2024-3 기출 → OOAAA */
m[0] = "A"; m[1] = "A"; m[2] = new String("A");
m[0].equals(m[1])   // 내용 비교 → O
m[1].equals(m[2])   // new String이어도 내용 같음 → O
비교배열String 리터럴new String
==참조 — 항상 별개풀 공유로 같을 수 있음항상 별개 객체
equals(Object 상속) 참조 비교내용 비교내용 비교

함정 조합 — 문제가 equals면 new String도 같다. 문제가 ==면 내용이 같아도 다르다. 어느 쪽 연산자인지에 밑줄부터 긋는다.


3. 생성자 체이닝과 "실행 순서" 문항

/* 2024-1 기출 — ①~⑦ 실행 순서: ⑤⑥③①⑦② */
Child(int x) {          // ③ 생성자에 먼저 '진입'하고
    super(x + 1, x);    //    첫 줄 super가 Parent ① 실행
    this.x = x;
}
  • new Child(3): Child 생성자 진입(③) → super() → Parent 생성자(①) → 복귀. 시험 관례상 "③ → ①" 순서로 적는다 (진입이 먼저).
  • 자식에 getT(int n)처럼 시그니처가 다른 메서드는 오버라이드가 아니다 — 부모 참조로 getT()를 부르면 부모 것이 실행된다(§1.3과 같은 원리).
  • 부모에 기본 생성자가 없으면 자식 생성자 첫 줄은 반드시 super(인자) (2025-3 기출 — 빈칸 정답 super). 자기 클래스의 다른 생성자는 this(...).

3.1 생성자 안에서 부른 메서드도 동적 바인딩 (2025-1 기출 → 54)

class Parent {
    static int total = 0;
    public Parent() { total += (++v); show(); }   // ← 이 show()는 Child.show()다!
    public void show() { total += total; }
}
class Child extends Parent {
    public Child() { v += 2; total += v++; show(); }
    @Override public void show() { total += total * 2; }
}
new Child();
System.out.println(Parent.total);

total 하나(static)에 모든 단계가 누적된다 — 한 줄씩 값을 적어 굴린다:

단계실행total
Child() → 암묵적 super() → Parent()total += ++v (Parent.v 1→2)2
Parent()의 show()동적 바인딩으로 Child.show()total += total*2 = 2+46
Child() 몸통: v += 2(Child.v 10→12), total += v++6 + 1218
Child()의 show() → Child.show()18 + 3654

함정 2연발 — ① 부모 생성자 몸통에서 호출해도 재정의된 메서드는 자식 버전(Child.show, total의 3배)이 불린다. ② Parent와 Child가 각자 v 필드를 갖는데, super()는 Parent.v(1)를, 몸통은 Child.v(10)를 쓴다(필드 섀도잉 §1.2). static total은 클래스당 하나라 전 단계가 쌓인다.

3.2 super.메서드() 는 이어 붙이기 (2026-2 기출 → 10a20b)

@Override void print() { super.print(); System.out.print(b + "b"); } — 부모 출력(10a)이 먼저, 자식 출력(20b)이 뒤. 순서만 정확히.


4. 예외 처리 — 매칭은 위에서부터, finally는 무조건

/* 2025-1 기출 → 출력1출력5 */
try { System.out.print(a / b); }               // 5/0 → ArithmeticException
catch (ArithmeticException e) { ... }           // ← 첫 매칭 하나만 실행
catch (Exception e) { ... }                     // 실행 안 됨
finally { ... }                                 // 항상 실행
/* 2024-3 기출 → 101 */
static void func() throws Exception { throw new NullPointerException(); }
/* 선언이 throws Exception이어도, 매칭은 '실제 던져진 객체' NPE 기준
   → catch(NullPointerException) +1 → finally +100 → 101 */

규칙 3개면 끝난다: ① 구체 타입 catch가 먼저 선언돼 있으면 그쪽이 잡는다 ② catch는 하나만 실행된다 ③ finally는 예외 여부·return 여부와 무관하게 실행된다.

람다 버전(2025-2 기출 → 19): 함수형 인터페이스의 apply(3)이 조건에 걸려 throw하면 run()의 catch가 7을 반환 — 람다여도 예외 흐름 규칙은 동일하다.


5. 문자열 — + 는 좌에서 우로, split은 조각 배열

/* 2026-1 기출 → 1123 */
int x1 = 9, x2 = 2;  String x3 = "3";
System.out.println(x1 + x2 + "2" + x3);
/* (9+2)=11 산술 → 11+"2"="112" 연결 → +"3" → "1123" */

+는 좌→우 결합. int끼리 만나는 동안만 덧셈이고, String을 만나는 순간부터 전부 연결이다. "9223"(전부 연결)과 "16"(전부 덧셈)이 양쪽 대표 오답.

/* 2024-2 기출 → S */
"ITISTESTSTRING".split("T")   // {"I", "IS", "ES", "S", "RING"}
result[3]                      // "S" — TT 연속 구간은 사이 문자로 갈린다

split은 구분자를 버리고 조각을 담는다. 조각을 0번부터 나열한 표를 그리고 인덱스를 센다.


6. static 필드 = 클래스당 하나 (싱글톤 포함)

/* 2024-1 기출 → 4 */
static public Connection get() {
    if (_inst == null) { _inst = new Connection(); }
    return _inst;                 // 항상 같은 인스턴스
}
/* conn1·conn2·conn3 전부 동일 객체 — count() 4회 → 4 */

참조 변수가 몇 개든 인스턴스가 하나면 필드도 하나다. §3.1의 Parent.total도 같은 원리(클래스당 하나)로 모든 생성자·메서드 호출이 한 변수에 누적됐다.


7. 참조 전달 — 무엇이 호출부에 남는가

/* 2025-2 기출 → BB */
public static void change(String[] data, String s) {
    data[0] = s;   // 배열 '원소' 수정 → 호출부에 보인다
    s = "Z";       // 매개변수 '재대입' → 호출부와 무관
}
/* 2025-2 기출 → 1a3b3 */
BO[] arr = {a, b, c};
BO t = arr[0]; arr[0] = arr[2]; arr[2] = t;   // 배열 '칸'의 참조만 교환
arr[1].v = arr[0].v;                           // b.v = c.v = 3 (객체 내용 수정)
System.out.println(a.v + "a" + b.v + "b" + c.v);  // 변수 a,b,c 기준!

구분 훈련 — ① 배열 칸의 참조 교환은 변수(a, b, c)에 아무 일도 하지 않는다. ② .필드 = 값만이 객체 내용을 바꾸고, 그 객체를 가리키는 모든 변수에 보인다. ③ 출력이 배열 기준인지 원래 변수 기준인지 마지막에 반드시 확인.


8. enum — values()와 name()

/* 2025-3 기출 → AB */
enum Tri { A("A"), B("AB"), C("ABC"); ... }
Tri t = Tri.values()[Tri.A.name().length()];
/* name() = 상수 이름 "A" → 길이 1 → values()[1] = B → B.code() = "AB" */
  • values()선언 순서의 배열, name()은 상수 이름 그대로, ordinal()은 선언 인덱스.
  • 생성자 인자로 받은 필드(code)와 상수 이름(name)을 구분하는 것이 함정의 전부다.

9. 재귀·분할정복 — 호출 트리로 굴린다

/* 2025-1 기출 → 20 */
static int func(int[] a, int st, int end) {
    if (st >= end) return 0;
    int mid = (st + end) / 2;
    return a[mid] + Math.max(func(a, st, mid), func(a, mid + 1, end));
}
/* func(0,4)=a[2]+max(func(0,2)=8, func(3,4)=12) = 8+12 = 20 */
/* 2025-1 기출 → 4 — 오버로딩 갈림 재귀 */
static int calc(int value)  { ... calc(value-1) + calc(value-2); }
static int calc(String str) { ... calc(value-1) + calc(value-3); }
calc("5");   /* String 버전은 최초 1회만 — value-1, value-3은 int라
                이후 전부 int 버전(피보나치형) → calc(4)+calc(2) = 3+1 = 4 */

String/int 오버로드가 섞인 재귀는 인자의 정적 타입이 어느 오버로드를 고르는지를 호출마다 표기하며 트리를 그린다. §1.3의 컴파일 타임 선택 규칙이 재귀에도 그대로 적용된다.

재귀 중복 제거(2024-2 기출 → dcba): 되돌아오며 c + result앞에 붙이는지 result + c로 뒤에 붙이는지, seen 배열이 무엇을 거르는지 — 붙이는 방향에 밑줄.


10. Java 문법 빠른 참조 (코드 문항 어디서든)

  • 기본형 vs 참조형: int·double·char·boolean(값 자체) vs 객체(참조). 래퍼 클래스 Integer·Double·Character·Boolean. 오토박싱(int↔Integer 자동 변환).
  • 정수 나눗셈: 7/2=3(int끼리 몫), 7.0/2=3.5. %는 나머지. char는 정수처럼 연산 ('A'+1 → 66, (char)('A'+1) → 'B').
  • 형변환: 작은 타입→큰 타입은 자동, 반대는 명시 (int)3.9=3(버림). 문자열→숫자는 Integer.parseInt("5"), 숫자→문자열은 String.valueOf(x) 또는 ""+x.
  • 문자열 메서드: .length(), .charAt(i), .substring(a,b)(b 미포함), .split(구분자), .equals()(내용), ==(참조), .indexOf(), .replace(). String은 불변.
  • 배열: int[] a = new int[5](기본값 0), a.length(괄호 없음 — 문자열의 length()와 다름), Arrays.equals()로 내용 비교.
  • 증감·연산자: 전위 ++x/후위 x++, 논리 &&/||/!, 비트 &/|/^/~, 시프트 <</>>/>>>(부호 없는).
  • 접근 제어자: public(전체) > protected(같은 패키지+자식) > (default, 같은 패키지) > private(자기 클래스). static(클래스 소속), final(상수·상속/재정의 금지).
  • 삼항: 조건 ? a : b. Math: Math.max/min/abs/pow/sqrt.

11. 고난도 함정 (자체 출제 hard 세트 대비)

기출엔 아직 안 나왔지만 나올 수 있는 Java 함정. 각 항목은 hard 세트의 실제 문항이다.

11.1 Integer 캐시 — ==가 값에 따라 갈린다

Integer x = 100, y = 100;   // x == y → true  (캐시)
Integer p = 200, q = 200;   // p == q → false (캐시 밖)

오토박싱은 −128~127 범위의 Integer를 캐시해 같은 객체를 재사용한다. 그 범위 안이면 ==가 true, 벗어나면 매번 새 객체라 false다. 래퍼 값 비교는 언제나 .equals() 로. 기본형 int끼리의 ==는 값 비교라 이 함정과 무관하다.

11.2 Java switch도 fall-through

switch (n) {           // n=2
    case 1: s += 1;
    case 2: s += 2;    // 진입, break 없음
    case 3: s += 3;    // 흘러내림
    default: s += 10;  // 여기까지
}                       // s = 2+3+10 = 15

C와 똑같이 break가 없으면 아래 case로 흘러내린다. (자바 14+의 화살표 case ->는 fall-through가 없지만, 실기 코드는 전통 case : 형태다.)

11.3 생성자에서 부른 가상 메서드 — 자식 필드는 아직 0

class P { int x = 10; P() { x = add(); } int add() { return x + 1; } }
class C extends P { int y = 5; int add() { return y + 100; } }
new C();   // P() 실행 시 add()는 C.add() (동적 바인딩), 그러나 y는 아직 0 → x=100

초기화 순서: 부모 생성자 → 자식 필드 초기화 → 자식 생성자. 부모 생성자가 도는 시점엔 자식 필드가 아직 기본값(0/null) 이다. 그 상태에서 재정의 메서드(C.add)가 불리면 y=0으로 계산된다(100). 이후 y=5로 초기화되어 최종 x=100, y=5.

11.4 삼항 연산자의 숫자 타입 승격

Object o = true ? Integer.valueOf(1) : Double.valueOf(2.0);   // o = 1.0 (Double)

삼항의 두 갈래가 Integer와 Double이면 공통 수치 타입 double로 승격된다 — 조건이 참이라 1이 선택돼도 타입은 이미 double이라 1.0으로 나온다. 값 선택보다 타입 결정이 먼저다.

11.5 자주 쓰는 라이브러리

  • Arrays.sort(arr)오름차순 in-place 정렬(반환값 없음). 정렬 후 arr[0]이 최소, arr[length-1]이 최대.
  • Arrays.equals(a, b)는 내용 비교(배열의 ==·equals는 참조 비교).
  • Integer.parseInt("5"), String.valueOf(x), Math.max/min/abs.

12. 시험장 체크리스트

  1. 참조 타입과 실제 객체 타입을 코드 옆에 나란히 적는다 (P tmp = new C() → P/C).
  2. 인스턴스 메서드만 실제 객체를 따른다. static·필드·오버로드 선택은 참조 타입.
  3. 자식의 같은 이름 메서드가 시그니처까지 같은지 확인 — 다르면 오버로드일 뿐.
  4. 생성자: 진입(자식) → super(부모) → 몸통. 그 안의 가상 호출은 자식 버전.
  5. 예외: 던져진 '객체'의 타입으로 위에서부터 매칭, 하나만, finally 무조건.
  6. + 연쇄는 좌→우로 타입을 추적. String 등장 이후는 전부 연결.
  7. 출력 대상이 배열인지 변수인지, name()인지 필드인지 — 마지막 확인.

출처

  • 2024-1 ~ 2026-2 실기 복원 기출 (이 트랙 수록 8회차) — 기사퍼스트·두목넷·수제비(공개 미러)·뉴비티·chobopark 교차 검증
  • 본문 코드 전량 javac(21) 컴파일·실행 검증 완료
C 언어 — 코드 추적 함정Python — 슬라이스·가변 객체