생성자 실행 순서, 오버라이딩과 동적 바인딩, 필드 가림, 추상 클래스와 인터페이스, 예외 처리·컬렉션·String 비교를 실행 결과로 정리합니다.
🎯 이 강의 학습 목표
출제기준 위치는 [3과목 프로그래밍 언어 활용 › 2. 프로그래밍 언어 활용 › 2. 언어특성 활용 › 2. 객체지향 프로그래밍 언어]와 [› 3. 라이브러리 활용 › 1. 라이브러리 · 3. 예외 처리]입니다. Java 문제는 「부모 타입 변수로 부른 메서드가 누구의 것인가」, 「finally가 언제 실행되는가」처럼 실행 순서를 따라가는 형태가 많습니다. 이 강을 마치면 다음을 할 수 있습니다.
- 생성자 실행 순서와 업캐스팅 상태에서 메서드·필드·static 메서드가 결정되는 기준을 설명한다.
- 추상 클래스와 인터페이스, 접근 제어자 네 가지를 구분한다.
- try-catch-finally 출력 순서, checked·unchecked 예외, == 와 equals()를 구분한다.
💡 클래스·상속·다형성
클래스는 필드·메서드·생성자를 묶은 설계도이고, new로 만든 실체가 객체입니다. 생성자는 클래스 이름과 같고 반환형을 쓰지 않습니다. 생성자를 하나도 쓰지 않으면 컴파일러가 매개변수 없는 기본 생성자를 넣지만, 매개변수 있는 생성자를 하나라도 직접 쓰면 기본 생성자는 생기지 않습니다. 생성자에서 this(...)나 super(...)를 명시하지 않으면 컴파일러가 super()를 넣으므로, 객체를 만들면 가장 위 조상의 생성자 본문부터 실행됩니다.
접근 제어자는 넓은 순서로 public(모든 곳) > protected(같은 패키지 + 다른 패키지의 자식) > 제어자 없음(같은 패키지) > private(같은 클래스)입니다. protected를 「자식만」으로, 제어자 없음을 private로 착각하는 선지가 자주 나옵니다.
클래스는 extends로 하나만 상속합니다. 같은 클래스 안에서 이름은 같고 매개변수의 개수·타입이 다른 메서드를 여러 개 두는 것이 오버로딩(컴파일 시 결정, 반환형만 다르면 오류), 자식이 부모 메서드를 이름·매개변수 목록이 같게 다시 정의하는 것이 오버라이딩(실행 시 결정, 접근 범위를 좁힐 수 없음)입니다.
핵심은 업캐스팅입니다. Shape s = new Circle(2);에서 s.describe()처럼 인스턴스 메서드를 부르면 변수 타입이 아니라 실제 객체의 오버라이딩된 메서드가 실행됩니다(동적 바인딩). 반대로 필드와 static 메서드는 참조 변수의 선언 타입을 따릅니다. 자식이 같은 이름의 필드를 선언하면 부모 필드를 덮어쓰는 것이 아니라 가리는 것이기 때문입니다. final은 변수(재대입 불가)·메서드(재정의 불가)·클래스(상속 불가)에 붙어 뜻이 다릅니다.
| 구분 | 추상 클래스 | 인터페이스 |
|---|---|---|
| 키워드 | abstract class / extends | interface / implements |
| 개수 | 하나만 상속 | 여러 개 구현 가능 |
| 필드 | 일반 인스턴스 필드 가능 | 모두 public static final 상수 |
| 생성자 | 가질 수 있음(자식의 super로 호출) | 없음 |
| 메서드 | 추상·일반 메서드 혼합 | 추상(암묵적 public), Java 8부터 default·static |
둘 다 new로 직접 객체를 만들 수 없지만 변수 타입으로는 쓸 수 있습니다.
💡 예외 처리·컬렉션·String
모든 예외의 뿌리는 Throwable이고, 그 아래 복구를 기대하지 않는 Error와 프로그램이 처리할 수 있는 Exception이 있습니다. Java 언어 명세는 RuntimeException·Error와 그 하위 클래스를 unchecked, 나머지를 checked로 정의합니다. checked 예외(IOException·FileNotFoundException·SQLException 등)는 catch로 잡거나 throws로 선언하지 않으면 컴파일 오류이고, unchecked 예외(ArithmeticException·NullPointerException·ArrayIndexOutOfBoundsException·NumberFormatException 등)에는 이 강제가 없습니다.
실행 규칙은 넷입니다. ① try에서 예외가 나면 남은 문장을 건너뛰고 타입이 맞는 첫 catch 하나만 실행한다. ② 하위 예외 catch를 상위 Exception보다 먼저 써야 한다. ③ finally는 예외 여부와 관계없이, return을 만나도 실행된다. ④ 잡히지 않은 예외는 호출한 쪽으로 전파된다. throw는 예외를 지금 던지는 문장, throws는 던질 수 있다고 선언하는 절입니다.
컬렉션은 List(순서 있음·중복 허용: ArrayList, LinkedList), Set(중복 불허: HashSet, 넣은 순서의 LinkedHashSet, 정렬된 TreeSet), Map(키 중복 불허: HashMap, TreeMap)으로 나뉩니다. Map에 같은 키로 put하면 값이 덮어써지고, 없는 키를 get하면 null입니다.
String은 불변이라 toUpperCase() 같은 메서드는 새 문자열을 돌려줄 뿐 원본을 바꾸지 않습니다. ==는 같은 객체인지, equals()는 내용이 같은지를 비교하므로 리터럴과 new String("java")는 ==가 false, equals()가 true입니다. 반복 연결에는 동기화하지 않는 StringBuilder, 여러 스레드가 함께 쓸 때는 동기화된 StringBuffer를 씁니다.
아래는 JDK 21에서 java Main.java로 실행한 결과입니다.
public class Main {
static int check(int n) {
try {
if (n < 0) throw new IllegalArgumentException("음수");
return n * 2;
} catch (IllegalArgumentException e) {
System.out.println("catch " + e.getMessage());
return -1;
} finally {
System.out.println("finally");
}
}
public static void main(String[] args) {
Shape s = new Circle(2);
System.out.println(s.name + " " + s.describe());
System.out.println(check(5));
System.out.println(check(-1));
String a = "java", b = new String("java");
System.out.println((a == b) + " " + a.equals(b));
}
}
abstract class Shape {
String name = "도형";
Shape() { System.out.println("Shape 생성자"); }
abstract double area();
String describe() { return "넓이 " + area(); }
}
class Circle extends Shape {
String name = "원";
int r;
Circle(int r) {
super();
this.r = r;
System.out.println("Circle 생성자");
}
@Override
double area() { return 3 * r * r; }
}
Shape 생성자
Circle 생성자
도형 넓이 12.0
finally
10
catch 음수
finally
-1
false true
부모 생성자가 먼저 찍히고, s.name은 변수 타입 Shape 기준이라 「도형」입니다. describe()는 Shape에 있는 메서드지만 그 안에서 부른 area()는 실제 객체 Circle의 구현이라 3 × 2 × 2 = 12.0입니다. check(5)는 반환값 10이 정해진 뒤에도 finally가 먼저 출력되고 나서 main이 10을 찍습니다.
⚠️ 시험에 나오는 함정
| 혼동 쌍 | 구분 기준 |
|---|---|
| 오버로딩 vs 오버라이딩 | 같은 클래스·매개변수 다름·컴파일 시 결정 vs 상속 관계·시그니처 같음·실행 시 결정 |
| 업캐스팅 상태의 메서드 vs 필드 | 인스턴스 메서드는 실제 객체 기준, 필드·static 메서드는 변수 선언 타입 기준 |
| checked vs unchecked | 처리 강제(컴파일 오류) vs 강제 없음(RuntimeException·Error 계열) |
| == vs equals() | 같은 객체인가 vs 같은 내용인가 |
| protected vs 제어자 없음 | 같은 패키지 + 다른 패키지의 자식 vs 같은 패키지만 |
📝 핵심 요약 — 암기표
- 생성자 본문은 최상위 부모부터 실행, super()는 생략해도 자동 삽입
- 클래스 단일 상속, 인터페이스 다중 구현(필드는 public static final, 메서드는 암묵적 public abstract)
- 업캐스팅: 메서드는 객체 기준(동적 바인딩), 필드·static은 변수 타입 기준
- unchecked = RuntimeException + Error 계열, finally는 return이 있어도 실행
- List 순서·중복 허용, Set 중복 불허, Map 같은 키 put은 덮어쓰기·없는 키 get은 null
- String 불변, 내용 비교는 equals(), StringBuilder(비동기화)·StringBuffer(동기화)
이 주제의 자세한 이론과 실전문제 8문항은 필기+실기 과정 혜택 교재 「정보처리기사 필기 완전정복 50강」의 33·34강에서 다룹니다.
다음 19강 「Python과 언어의 특성」에서는 슬라이싱·가변 객체·클래스 같은 Python 문법과 절차적·객체지향·스크립트·선언형 언어 분류, 라이브러리와 프로토타입을 다룹니다.
📋 확인 문제
다음 Java 코드에서
A o = new B(); System.out.println(o.v + " " + o.get());의 출력은?class A { int v = 1; int get() { return v; } } class B extends A { int v = 2; int get() { return v; } }① 1 1
② 2 2
③ 2 1
④ 1 2다음 메서드에 대해
System.out.println(run("12") + " " + run("x"));의 출력은?static String run(String s) { StringBuilder sb = new StringBuilder(); try { sb.append("A"); Integer.parseInt(s); sb.append("B"); } catch (NumberFormatException e) { sb.append("C"); } finally { sb.append("D"); } return sb.toString(); }① ABD ABCD
② ABD ACD
③ ABCD ACD
④ AB ACD다음 중 checked 예외로, 처리하거나 throws로 선언하지 않으면 컴파일 오류가 나는 것은?
① NullPointerException
② ArithmeticException
③ IOException
④ ArrayIndexOutOfBoundsExceptionJava 인터페이스에 대한 설명으로 옳은 것은?
① 인터페이스에 선언한 필드는 자동으로 public static final 상수가 된다.
② 인터페이스는 생성자를 가질 수 있어 new로 객체를 만들 수 있다.
③ 한 클래스는 인터페이스를 하나만 implements할 수 있다.
④ 인터페이스의 추상 메서드를 구현할 때 public을 빼도 된다.다음 코드의 출력은?
String a = "eip", b = new String("eip"); List<Integer> list = new ArrayList<>(List.of(3, 1, 3, 2)); Map<String, Integer> m = new HashMap<>(); m.put("k", 1); m.put("k", 2); System.out.println((a == b) + " " + a.equals(b) + " " + new HashSet<>(list).size() + " " + m.get("k"));① true true 3 2
② false true 4 2
③ false true 3 2
④ false false 3 1
✅ 정답과 해설
정답 ④ — 필드 o.v는 변수 타입 A 기준이라 1, 오버라이딩된 get()은 실제 객체 B의 것이 실행되어 B의 v인 2를 돌려줍니다. ②는 필드까지 객체 기준으로 본 오답, ①은 메서드까지 변수 타입 기준으로 본 오답입니다(JDK 21 실행으로 확인).
정답 ② — "12"는 변환에 성공해 A·B 다음 finally의 D가 붙어 ABD입니다. "x"는 parseInt에서 NumberFormatException이 나 B를 건너뛰고 C, 이어서 D가 붙어 ACD입니다. ①·③은 예외 뒤의 B가 실행된다고 본 오답, ④는 finally를 빠뜨린 오답입니다.
정답 ③ — IOException은 RuntimeException 계열이 아니므로 checked 예외입니다. 나머지 셋은 모두 RuntimeException의 하위 클래스라 unchecked입니다.
정답 ① — 인터페이스 필드는 public static final이 자동으로 붙습니다. 인터페이스는 생성자가 없고 new로 만들 수 없으며(②), 여러 개를 동시에 구현할 수 있고(③), 암묵적 public 메서드를 구현할 때 public을 빼면 접근 범위가 좁아져 컴파일 오류입니다(④).
정답 ③ — new로 만든 b는 다른 객체라 ==는 false, 내용은 같아 equals()는 true입니다. HashSet은 중복 3을 하나로 쳐 크기 3이고, 같은 키 "k"에 두 번 put하면 값이 2로 덮어써집니다. ②는 List 크기를 쓴 값, ④는 첫 put 값이 남는다고 본 오답입니다.
📚 참고 자료
관련 주제
- 정보처리기사
- 필기
- 3과목
- Java
- 상속
- 다형성
- 예외 처리
- 컬렉션
- 자격증
- 자격증 강의
- 정보처리기사 필기 25강 — 2027 출제기준 핵심 요약
- 무료강의
- 무료 온라인 강의
- NUGUNA
- 누구나
📚 시리즈 전체 공유
정보처리기사 필기 25강 — 2027 출제기준 핵심 요약
이 강의가 속한 시리즈는 총 25강, 모두 무료입니다. 처음부터 배우려는 동료에게 시리즈 전체를 알려 주세요.
댓글
불러오는 중...
