Bclass A {
void show() {
System.out.println("A");
}
}
class B extends A {
void show() {
System.out.println("B");
}
}
public class Main {
public static void main(String[] args) {
A obj = new B();
obj.show();
}
}
A obj = new B(); // 업캐스팅
obj.show(); // 오버라이딩된 B의 show() 호출됨 → 동적 바인딩
정답 출력:
B
2import java.util.HashSet;
class User {
String name;
User(String name) {
this.name = name;
}
}
public class Main {
public static void main(String[] args) {
HashSet<User> set = new HashSet<>();
set.add(new User("kim"));
set.add(new User("kim"));
System.out.println(set.size());
}
}
HashSet은 equals()와 hashCode()를 기준으로 중복 제거User("kim")은 내용은 같아도 다른 객체 → equals, hashCode 미오버라이딩 시 다른 객체로 판단됨정답 출력:
2
public class Main {
public static void main(String[] args) {
int[] a = {1, 2, 3};
int[] b = a;
b[1] = 99;
int[] c = a.clone();
c[2] = 100;
System.out.println(a[1]);
System.out.println(a[2]);
}
}
99
3
b = a → 같은 배열 참조 → a[1] = 99c = a.clone() → 깊은 복사 → c[2] = 100은 a에 영향 없음정답 출력:
99
3
public class Main {
public static void main(String[] args) {
int n = 2;
switch(n) {
case 1:
System.out.print("one ");
case 2:
System.out.print("two ");
case 3:
System.out.print("three ");
break;
default:
System.out.print("default ");
}
}
}
two three
case 2:부터 실행됨 → break 없음 → case 3도 실행case 1은 n이 2이므로 건너뜀정답 출력:
two three
Ainterface A {
default void show() {
System.out.println("A");
}
}
interface B {
default void show() {
System.out.println("B");
}
}
class C implements A, B {
public void show() {
A.super.show();
}
}
public class Main {
public static void main(String[] args) {
C obj = new C();
obj.show();
}
}
A, B 둘 다 show()를 갖고 있어 충돌 발생A.super.show()로 특정 인터페이스 호출 지정 가능정답 출력:
A
| 문제 번호 | 주제 | 정답 / 출력 |
|---|---|---|
| 6 | 오버라이딩 + 업캐스팅 | B |
| 7 | equals/hashCode 미정의 | 2 |
| 8 | 참조 vs 복사 | 99 3 |
| 9 | switch break 누락 | two three |
| 10 | 인터페이스 default 충돌 + 명시 호출 | A |
public class Main {
public static void main(String[] args) {
String str = "abc";
StringBuilder sb = new StringBuilder("abc");
str.concat("def");
sb.append("def");
System.out.println(str);
System.out.println(sb);
}
}
abc
abcdef
String은 불변(immutable) → str.concat("def")는 원본에 영향 없음StringBuilder는 가변(mutable) → sb.append("def")는 원본 변경됨class Animal {}
class Dog extends Animal {}
public class Main {
public static void main(String[] args) {
Animal a = new Dog();
if (a instanceof Animal)
System.out.print("Animal ");
if (a instanceof Dog)
System.out.print("Dog ");
}
}
Animal Dog
a는 Dog 타입의 인스턴스이므로 두 조건 다 trueinstanceof 연산자의 정체instanceof는 객체가 특정 클래스(또는 그 자식)인지 확인할 때 사용하는 논리 연산자야.
결과는 true 또는 false (boolean 값)으로 나와.
객체참조변수 instanceof 클래스명
| 역할 | 상세 설명 |
|---|---|
| 1. 객체의 실제 타입 확인 | 런타임 시점에 객체가 특정 클래스(또는 그 하위 클래스)인지 확인 |
| 2. 안전한 다운캐스팅 전 검사 | 강제 형변환((Dog) a) 전에 그 객체가 진짜 Dog인지 확인 |
| 3. 타입에 따라 다른 처리 | 조건문으로 객체의 타입에 따라 서로 다른 로직을 처리할 수 있게 해줌 |
null은 항상 falseAnimal a = null;
System.out.println(a instanceof Animal); // false
→ 이유: null은 어떤 객체도 가리키지 않기 때문에, 타입과 무관하게 무조건 false
ClassCastException→ 그래서 instanceof로 먼저 확인하고 형변환해야 해
Animal a = new Animal();
Dog d = (Dog) a; // 런타임 오류! Animal은 Dog가 아님!
해결 방법:
if (a instanceof Dog) {
Dog d = (Dog) a; // 안전하게 캐스팅
}
instanceof는 상속 관계 또는 인터페이스 구현 관계가 있어야 검사 가능해.
예:
interface Pet {}
class Cat implements Pet {}
Pet p = new Cat();
System.out.println(p instanceof Cat); // true
| 항목 | 설명 |
|---|---|
| 역할 | 객체가 특정 타입인지 확인 (true/false) |
| 언제 사용? | 다운캐스팅 전에 안전성 검사할 때, 타입에 따라 분기할 때 |
| 특징 | 런타임 시점 검사, 상속·인터페이스만 가능, null은 항상 false |
| 주의점 | instanceof 없이 형변환하면 위험, 반드시 체크하고 캐스팅할 것 |
public class Main {
public static void main(String[] args) {
try {
int x = 5 / 0;
System.out.println("Try block");
} catch (ArithmeticException e) {
System.out.println("Catch block");
} finally {
System.out.println("Finally block");
}
}
}
Catch block
Finally block
5 / 0 예외 발생 → try 블록 종료, catch로 이동 → 그 후 finally는 항상 실행됨class Test {
static {
System.out.println("Static Block");
}
Test() {
System.out.println("Constructor");
}
}
public class Main {
public static void main(String[] args) {
Test t1 = new Test();
Test t2 = new Test();
}
}
Static Block
Constructor
Constructor
static block은 단 한 번만 실행됨class Parent {
int x = 10;
}
class Child extends Parent {
int x = 20;
void print() {
System.out.println("x = " + x);
System.out.println("super.x = " + super.x);
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
c.print();
}
}
x = 20
super.x = 10
Child 클래스에 x가 다시 정의됨 (shadowing)super.x는 부모의 필드 접근class Holder {
int val = 10;
}
public class Main {
public static void change(int x, Holder h) {
x = 20;
h.val = 30;
}
public static void main(String[] args) {
int a = 5;
Holder h = new Holder();
change(a, h);
System.out.println("a = " + a);
System.out.println("h.val = " + h.val);
}
}
a = 5
h.val = 30
int는 기본형 → 함수 내 변경이 원본에 영향 XHolder는 참조형 → 객체 내부 값 변경은 반영됨| 문제 번호 | 개념/트릭 주제 | 정답 / 출력 |
|---|---|---|
| 11 | String 불변성, StringBuilder 가변성 | abc / abcdef |
| 12 | instanceof 다형성 조건 검사 | Animal Dog |
| 13 | 예외 처리 흐름 + finally | Catch block / Finally block |
| 14 | static block vs constructor 순서 | Static Block / Constructor x2 |
| 15 | 변수 숨김 (shadowing) | 20 / 10 |
| 16 | 기본형 vs 참조형 인자 차이 | 5 / 30 |
| 구분 | 개념 요약 |
|---|---|
| String vs StringBuilder | String은 immutable, append는 영향 없음 |
| instanceof | 상속 받은 객체는 부모와 자식 모두 만족 |
| try-catch-finally | finally는 무조건 실행됨 |
| static vs constructor | static block은 클래스 로딩 시 1회 |
| 변수 shadowing | 같은 이름이면 자식 변수 우선, super로 부모 접근 |
| 기본형 vs 참조형 | 기본형은 값 복사, 참조형은 주소 복사 (내부 변화 반영됨) |
좋아! 이번엔 지금까지 나온 걸 제외한 새로운 트랩 유형 위주로 문제를 구성할게.
실제 정보처리기사 실기 시험이나 객관식/단답식/코드 실행 결과 예측 문제로 나올 수 있는 스타일로 낼게.
| 유형 번호 | 개념 트랩 주제 |
|---|---|
| 17 | 배열을 파라미터로 넘길 때 주의할 점 |
| 18 | 배열 초기화 안 한 상태에서의 값 |
| 19 | 조건문의 중첩과 else 붙는 위치 |
| 20 | char와 int의 연산 |
| 21 | 자동 형변환 vs 명시적 형변환 |
| 22 | 전위/후위 연산자의 동작 순서 |
public class Main {
public static void modify(int[] arr) {
arr[0] = 999;
}
public static void main(String[] args) {
int[] nums = {1, 2, 3};
modify(nums);
System.out.println(nums[0]);
}
}
999arr[0] = 999 하면 원본도 바뀜0public class Main {
public static void main(String[] args) {
int[] a = new int[3];
System.out.println(a[1]);
}
}
int[]는 선언 시 모든 값이 0으로 초기화됨Bpublic class Main {
public static void main(String[] args) {
int x = 5;
if (x > 3)
if (x > 10)
System.out.println("A");
else
System.out.println("B");
}
}
else는 가장 가까운 if에 붙음if (x > 3) // true
if (x > 10) // false
...
else // ← 이 else는 위의 if(x > 10)에 붙음
66public class Main {
public static void main(String[] args) {
char ch = 'A';
int val = ch + 1;
System.out.println(val);
}
}
'A'는 유니코드 6565 + 1 = 66-118public class Main {
public static void main(String[] args) {
byte b = 10;
int i = b;
byte c = (byte)(i + 128);
System.out.println(c);
}
}
i + 128 = 10 + 128 = 138
(byte)138 → 바이트 오버플로우:
138 - 256 = -118
5 + 7 = 12public class Main {
public static void main(String[] args) {
int a = 5;
int b = a++ + ++a;
System.out.println(b);
}
}
a++ → 5 (후위, 사용 후 증가)++a → 7 (앞에서 이미 6 되었음, 전위 증가로 7)정답: 12
| 문제 번호 | 개념 주제 | 정답 |
|---|---|---|
| 17 | 배열 참조 | 999 |
| 18 | 배열 초기값 | 0 |
| 19 | 중첩 if-else | B |
| 20 | char + int 연산 | 66 |
| 21 | 형변환 overflow | -118 |
| 22 | 전위/후위 연산 순서 | 12 |
| 트릭 구분 | 핵심 요약 설명 |
|---|---|
| 배열 전달 | 참조형이므로 내부 변경 = 외부 변경 |
| int[] 선언 | 자동으로 0으로 초기화 |
| else 위치 | 가장 가까운 if와 짝을 이룸 |
| char + int | char는 숫자처럼 계산됨 |
| byte 형변환 | 128 이상이면 오버플로우 |
| a++ + ++a | 후위 먼저, 그다음 전위 증가 |