문제 1: 접근제어자 & 상속
class Parent {
private void show() {
System.out.println("Parent 클래스");
}
}
class Child extends Parent {
public void show() {
System.out.println("Child 클래스");
}
}
public class Test {
public static void main(String[] args) {
Parent obj = new Child(); obj.show();
}
}
Q1: 위 코드의 실행 결과는 무엇인가?
- Child 클래스 출력
- Parent 클래스 출력
- 컴파일 에러 발생
- 런타임 에러 발생
✅ 정답: 3) 컴파일 에러 발생
💡 설명:
Parent
의show()
메서드는private
이라 상속되지 않음.Child
의show()
는 완전히 다른 메서드(오버라이딩이 아님).Parent obj = new Child();
이후obj.show()
는 컴파일 시점에Parent
가 가진show()
를 찾는데,private
때문에 존재하지 않아 오류가 발생함.
문제 2: final 변수와 참조형 변수
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
final List list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list = new ArrayList<>(); // 문제 발생?
}
}
Q2: 위 코드에서 어떤 문제가 발생할까?
- final인데
list.add()
가 가능하므로 오류 발생 list = new ArrayList<>();
에서 컴파일 에러 발생- 정상적으로 실행됨
- 런타임 예외 발생
✅ 정답: 2) list = new ArrayList<>();
에서 컴파일 에러 발생
💡 설명:
final
은 재할당을 막을 뿐, 내부 요소 변경(add()
)은 허용함.- 하지만
list = new ArrayList<>();
처럼 새 객체로 재할당은 불가능하기 때문에 컴파일 에러.
문제 3: for-loop와 i++ 값 예측
public class Test {
public static void main(String[] args) {
int i = 0;
for (int j = 0; j < 5; j++) {
if (j % 2 == 0) {
i++;
}
}
System.out.println(i);
}
}
Q3: 위 코드 실행 후 i의 값은 무엇인가?
- 2
- 3
- 4
- 5
✅ 정답: 2) 3
💡 설명:
j % 2 == 0
이 참인 경우는 j=0,2,4 → 총 3번i++
진행.- 따라서 최종
i
는 3.
문제 4: String, StringBuilder 차이점
public class Test {
public static void main(String[] args) {
String str = "Hello";
str.concat(" World");
System.out.println(str);
}
}
Q4: 위 코드 실행 후 출력 결과는?
- Hello World
- Hello
- World
- 컴파일 에러 발생
✅ 정답: 2) Hello
💡 설명:
String
은 불변(Immutable) 객체이므로concat()
은 새로운 문자열을 반환하지만, 반환값을str
에 다시 할당하지 않으면 원본은 바뀌지 않음.- 따라서 콘솔엔
Hello
가 그대로 출력됨.
문제 5: 예외 발생 여부
public class Test {
public static void main(String[] args) {
try {
int result = 10 / 0;
System.out.println("결과: " + result);
} catch (ArithmeticException e) {
System.out.println("예외 발생!");
} finally {
System.out.println("Finally 블록 실행!");
}
}
}
Q5: 위 코드 실행 결과는?
- 결과: 0
- 예외 발생!
- 예외 발생! + Finally 블록 실행!
- 런타임 에러 발생 후 프로그램 종료
✅ 정답: 3) 예외 발생! + Finally 블록 실행!
💡 설명:
10 / 0
으로ArithmeticException
발생 → catch 블록에서 "예외 발생!" 출력finally
블록은 예외와 상관없이 무조건 실행되므로 "Finally 블록 실행!"도 출력됨
문제 6: static 변수와 인스턴스 변수
class Test {
static int a = 0; int b = 0;
public Test() {
a++;
b++;
}
public static void main(String[] args) {
Test obj1 = new Test();
Test obj2 = new Test();
System.out.println("a: " + obj1.a + ", b: " + obj1.b);
}
}
Q6: 실행 결과는?
- a: 2, b: 1
- a: 2, b: 2
- a: 1, b: 1
- a: 2, b: 0
✅ 정답: 1) a: 2, b: 1
💡 설명:
a
는static
이므로 인스턴스를 여러 개 만들어도 공유 → 최종 2b
는 인스턴스 변수이므로obj1
과obj2
각각 1씩 가지고 있음. 출력 시점에는obj1
기준으로b = 1
문제 7: 자바의 다형성
class Animal {
void makeSound() {
System.out.println("동물이 소리를 낸다");
}
}
class Dog extends Animal {
void makeSound() {
System.out.println("멍멍");
}
}
public class Test {
public static void main(String[] args) {
Animal myDog = new Dog();
myDog.makeSound();
}
}
Q7: 위 코드 실행 결과는?
- 동물이 소리를 낸다
- 멍멍
- 컴파일 에러 발생
- 런타임 예외 발생
✅ 정답: 2) 멍멍
💡 설명:
- 다형성(polymorphism)으로
Animal
타입myDog
이지만, 실제 객체는Dog
- 오버라이딩된
makeSound()
→ "멍멍" 출력
문제 8: 예외 처리와 return
public class Test {
public static void main(String[] args) {
System.out.println(testMethod());
}
public static int testMethod() {
try {
return 1;
} finally {
return 2;
}
}
}
Q8: 위 코드 실행 결과는?
- 1
- 2
- 예외 발생 후 종료
- 컴파일 에러
✅ 정답: 2) 2
💡 설명:
finally
블록에서return 2
를 호출하면,try
블록의return 1
은 무시됨.- 결과적으로
2
가 최종 반환됨.
문제 9: 생성자 호출 순서
class Parent {
Parent() {
System.out.println("Parent 생성자");
}
}
class Child extends Parent {
Child() {
System.out.println("Child 생성자");
}
}
public class Test {
public static void main(String[] args) {
Child obj = new Child();
}
}
Q9: 실행 결과는?
- Child 생성자
- Parent 생성자
- Parent 생성자 + Child 생성자
- 컴파일 에러
✅ 정답: 3) Parent 생성자 + Child 생성자
💡 설명:
- 자식 객체 생성 시 부모 생성자가 먼저 호출됨.
- 출력 순서: "Parent 생성자" → "Child 생성자".
문제 10: 인터페이스와 메서드 호출
interface A {
default void show() {
System.out.println("A 인터페이스");
}
}
class B implements A {
public void show() {
System.out.println("B 클래스");
}
}
public class Test {
public static void main(String[] args) {
A obj = new B(); obj.show();
}
}
Q10: 실행 결과는?
- A 인터페이스
- B 클래스
- 컴파일 에러 발생
- 런타임 에러 발생
✅ 정답: 2) B 클래스
💡 설명:
default
메서드는 오버라이딩이 없을 때만 실행됨.B
클래스에서show()
를 오버라이딩했으므로 "B 클래스"가 출력됨.
문제 11: 오버로딩과 자동 타입 변환
class OverloadTest {
static String process(int x) {
return "int 버전 호출: " + x;
}
static String process(long x) {
return "long 버전 호출: " + x;
}
public static void main(String[] args) {
System.out.println(process(10));
}
}
Q11: 위 코드 실행 결과는?
- int 버전 호출: 10
- long 버전 호출: 10
- 컴파일 에러 발생
- 런타임 예외 발생
✅ 정답: 1) int 버전 호출: 10
💡 설명:
- 정수 리터럴
10
은 기본적으로int
형으로 인식 - 메서드 오버로딩 시,
int
에 더 적합한 메서드가 우선 선택됨
문제 12: 배열 vs 가변인자(Varargs)
class VarargsTest {
static int sum(int[] nums) {
int total = 0;
for(int n : nums) {
total += n;
}
return total;
}
static int sumVarargs(int... nums) {
int total = 0;
for(int n : nums) {
total += n;
}
return total;
}
public static void main(String[] args) {
int[] arr = {1,2,3};
System.out.println(sum(arr));
System.out.println(sumVarargs(1,2,3));
}
}
Q12: 위 코드 실행 결과로 옳은 것은?
- 6
6 - 오류 발생
- 1
2 - 6
3
✅ 정답: 1) 6, 6
💡 설명:
sum(int[])
는 배열을 받아 합계 계산sumVarargs(int...)
는 가변인자로 합계 계산- 둘 다 {1,2,3}의 합이므로 6
문제 13: 재귀 호출과 StackOverflowError
public class RecursionTest { public static void main(String[] args) { recurse(); }
static void recurse() {
System.out.println("재귀 호출 중...");
recurse();
}
}
Q13: 위 코드 실행 결과는?
- 무한히 "재귀 호출 중..." 출력 후 프로그램 정상 종료
- "재귀 호출 중..."가 한 번만 출력
- StackOverflowError 발생
- 컴파일 에러 발생
✅ 정답: 3) StackOverflowError 발생
💡 설명:
- 무한 재귀는 호출 스택을 계속 쌓게 되어
StackOverflowError
발생 - 재귀 종료 조건이 없으므로 무조건 에러로 종료
문제 14: Generics - <? extends Number> vs <? super Number>
import java.util.*;
public class GenericsTest {
public static void main(String[] args) {
List listInt = new ArrayList<>();
listInt.add(100);
List<? extends Number> listExtends = listInt;
// listExtends.add(200); // ?
List<? super Number> listSuper = new ArrayList<>();
listSuper.add(300); // ?
System.out.println(listInt.get(0));
}
}
Q14: 위 코드에서 주석(// ?
) 부분에 대한 설명으로 옳은 것은?
listExtends.add(200)
은 컴파일 에러가 발생하지 않는다listSuper.add(300)
은 컴파일 에러가 발생한다listExtends.add(200)
은 컴파일 에러,listSuper.add(300)
은 정상 동작- 둘 다 정상 컴파일되며 실행 시 에러
✅ 정답: 3) listExtends.add(200)
은 컴파일 에러, listSuper.add(300)
은 정상 동작
💡 설명:
? extends Number
는 “읽기 전용”으로 사용, add 시 컴파일 에러? super Number
는 “Number 이상의 타입” 추가 가능,listSuper.add()
문제 없음
문제 15: 내부 클래스(Inner Class)
public class InnerClassTest {
private String message = "Outer";
class Inner {
void printMessage() {
System.out.println(message);
}
}
public static void main(String[] args) {
InnerClassTest outer = new InnerClassTest();
InnerClassTest.Inner inner = outer.new Inner();
inner.printMessage();
}
}
Q15: 위 코드 실행 결과는?
- Outer
- null
- Inner
- 컴파일 에러 발생
✅ 정답: 1) Outer
💡 설명:
- 내부 클래스는 외부 클래스의 private 멤버에 직접 접근 가능
outer.new Inner()
를 통해 인스턴스 생성 가능
문제 16: 익명 클래스(Anonymous Class)
interface Greeting {
void sayHello();
}
public class AnonymousClassTest {
public static void main(String[] args) {
Greeting g = new Greeting() {
@Override
public void sayHello() {
System.out.println("Hello from Anonymous!");
}
};
g.sayHello();
}
}
Q16: 위 코드 실행 결과는?
- Hello from Anonymous!
- 컴파일 에러 발생
- 익명 클래스라 아무것도 출력되지 않음
- 런타임 예외 발생
✅ 정답: 1) Hello from Anonymous!
💡 설명:
- 익명 클래스는
new 인터페이스() { ... }
형태로 구현 sayHello()
오버라이딩 후 호출 시 메시지 출력
*문제 17: Thread 사용
public class ThreadTest extends Thread {
@Override
public void run() {
System.out.println("Thread 실행 중");
}
public static void main(String[] args) {
ThreadTest t = new ThreadTest();
t.start();
System.out.println("main 메서드");
}
}
Q17: 실행 결과가 "main 메서드"가 먼저 출력될 수도 있는 이유는?
- t.start()가 컴파일 에러를 유발해서
- Thread는 별도 실행 흐름이므로 main이 먼저 끝날 수 있음
- JVM 버그
- 시스템 환경 변수 문제
✅ 정답: 2) Thread는 별도 실행 흐름이므로 main이 먼저 끝날 수 있음
💡 설명:
start()
호출 시 새로운 쓰레드가 생성되어run()
실행- 메인 쓰레드와 병렬로 실행되므로 순서가 보장되지 않음
*문제 18: Callable & Future
import java.util.concurrent.*;
public class CallableTest {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new Callable<String>() {
@Override
public String call() {
return "Callable 결과";
}
});
System.out.println("메인 진행 중...");
System.out.println(future.get());
executor.shutdown();
}
}
Q18: future.get()
의 역할은?
- 비동기로 결과를 가져오지만 대기 없이 즉시 반환
- 스레드 실행 결과를 대기 후 받아옴
- Runtime 예외를 발생시킴
- 컴파일 시 에러를 발생시킴
✅ 정답: 2) 스레드 실행 결과를 대기 후 받아옴
💡 설명:
future.get()
은 작업이 완료될 때까지 블로킹(대기)- 완료된 후 Callable의 반환값을 가져옴
*문제 19: 람다 표현식
import java.util.Arrays;
import java.util.List;
public class LambdaTest {
public static void main(String[] args) {
List list = Arrays.asList("A", "B", "C");
list.forEach(s -> System.out.println(s));
}
}
Q19: 위 코드 실행 결과로 옳은 것은?
- A B C
- 컴파일 에러 발생
- 빈 출력
- 런타임 예외 발생
✅ 정답: 1) A B C
💡 설명:
list.forEach(s -> System.out.println(s));
람다식으로 각 요소를 출력- 결과적으로 A, B, C가 순차적으로 콘솔 출력
*문제 20: 스트림 중간 연산과 최종 연산
import java.util.Arrays;
public class StreamTest {
public static void main(String[] args) {
long count = Arrays.asList("apple", "banana", "avocado", "cherry").stream()
.filter(s -> s.startsWith("a"))
.map(String::toUpperCase)
.count();
System.out.println("결과: " + count);
}
}
Q20: 위 코드 실행 결과는?
- 결과: 1
- 결과: 2
- 컴파일 에러 발생
- 런타임 예외 발생
✅ 정답: 2) 결과: 2
💡 설명:
startsWith("a")
를 만족하는 문자열: "apple", "avocado"map(String::toUpperCase)
는 대문자로 변환하지만 개수엔 영향 없음- 최종 연산인
count()
로 2 반환
'Java' 카테고리의 다른 글
JAVA 문법 QUIZ [2] (2) | 2025.02.04 |
---|---|
Java 조각모음 [4] (1) | 2025.01.23 |
예제로 배우는 결국 알아야하는 JVM 메모리 구조(순한맛) (0) | 2025.01.22 |
예제로 배우는 제한자와 자바변수 설계 전략 (1) | 2025.01.22 |
예제로 배우는 자바가 배열을 생성하는 원리 이해하기 (0) | 2025.01.21 |