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() : 내용 비교
- == : 참조 비교
풀이
- main() 실행 시
- x[0] = "A"; // 문자열 리터럴 "A" x[1] = "A"; // 같은 리터럴이므로 같은 객체 참조 x[2] = new String("A"); // 새 객체 생성 (주소 다름)
- 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' 출력
- 첫 번째 for문:
- 두 번째 for문(for(String z : x))
- 각각 "A", "A", "A" 출력 → "AAA"
- 최종 출력:
- 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 로 변환됨
풀이과정
- main→ new Collection<>(0).print(); → Collection<Integer> 타입 생성
- 제네릭 타입 소거 : 컴파일 후
- public static class Collection { Object value; // T → Object로 변환! public void print() { new Printer().print(value); // value는 Object 타입! } }
- 메서드 오버로딩 선택
- value 의 타입은 Object
- void print(Object a) 선택
- 출력
- 처음에 전달한 수 가 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 에 나오는 문자를 반환
풀이
- 초기값
String str = "abacabcd";
boolean[] seen = new boolean[256];
System.out.print(calculFn(str, str.length()-1, seen));
- str = "abacabcd"
- index = 7 (마지막 문자 d)
- seen 배열은 전부 false로 초기화됨
- 재귀 호출
- 함수가 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" |
- 최종 결과
- 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 (스택 영역) | 메서드의 지역변수, 매개변수, 참조변수 | 메서드 호출 시 생성, 종료 시 자동 제거 |
풀이
- public static void main(String[] args) {
- JVM이 main() 메서드를 호출 → main 스택 프레임이 생성됨.
- 이 시점에서 아직 Connection 클래스의 객체는 없음.
- Connection 클래스 로딩
- Connection conn1 = Connection.get(); 구문이 실행되면 JVM은 Connection 클래스를 처음으로 사용하기 때문에 클래스 정보를 메서드 영역(Method Area) 에 로드한다.
- 이 시점에 메서드 영역에는 다음 정보가 올라간다.
- 정적 변수 _inst (초기값 null)
- 정적 메서드 get()
- 인스턴스 메서드 count()와 getCount()
- 아직 객체는 만들어지지 않았고, 단지 클래스 정의만 메모리에 존재한다.
- 첫 번째 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이 있고, 셋이 연결된 상태가 된다.
- conn1.count() 실행
- conn1이 가리키는 힙 객체의 count 필드가 0 → 1로 증가한다.
- 스택에는 아무 변화가 없고, 힙 영역의 객체 내부 값만 바뀐다.
- 두 번째 호출 Connection conn2 = Connection.get();
- 스택에 새로운 지역변수 conn2가 생긴다.
- 이번에 get()을 호출하면 _inst가 이미 null이 아니므로 새로운 객체를 만들지 않고 기존 _inst를 그대로 반환한다.
- 따라서 conn2도 conn1과 같은 힙 객체의 주소를 갖게 된다.
- conn2.count() 실행
- 같은 힙 객체의 count가 1 → 2로 증가한다.
- 세 번째 호출 Connection conn3 = Connection.get();
- 스택에 지역변수 conn3가 생긴다.
- _inst는 여전히 기존 객체를 가리키고 있으므로, conn3 역시 같은 힙 객체를 참조하게 된다.
- conn3.count() 실행
- 동일한 객체의 count가 2 → 3으로 증가한다.
- 다시 conn1.count() 실행
- conn1, conn2, conn3는 모두 같은 객체를 가리키므로 이 호출로 count가 3 → 4로 증가한다.
- 최종 출력
- 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
풀이
- main()
P obj = new C();
obj.calc(7);
- obj 의 실제 타입은 C → C 의 calc() 가 실행
- 계산
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
풀이
- 초기값 → w=3, x=4, y=3, z=5
- 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 블록 실행
- 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
풀이
- 반복 조건 판단
- n이 0이 되면 더 이상 나눌 수 없으므로 ① n > 0 (또는 n != 0)가 맞다.
- 현재 비트 계산
- 현재 n을 2로 나눈 나머지가 이번 단계의 2진수 비트이므로 ② n % 2.
- a[i++]에 저장하면서 인덱스 i가 1 증가한다. (하위 비트부터 a[0], a[1]...에 쌓임)
- 단계별 실행 추적 (초기: 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
- 문자열 → 숫자 변환 실패 예외
풀이
- int a = 5, b = 0;
- b가 0이므로 a / b 수행 시 ArithmeticException (산술 예외) 발생.
- 예외 발생 후 catch (ArithmeticException e) 블록 실행
- "출력1" 출력.
- 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
풀이
- new Child() : 객체 생성
- parent() → total += (++v)
- 부모의 v는 1 → ++v로 2
- total = 0 + 2 = 2
- 부모 생성자 안의 show() 호출
- 하지만 자식이 오버라이드한 show() 가 실행된다.
- total = 2 + (2 * 2) = 6
- parent() → total += (++v)
- 부모 생성자 종료 후, 자식 생성자 실행
- 현재 자식의 v = 10
- v += 2; → v = 12
- total += (v++); → total = 6 + 12 = 18, 이후 v = 13
- show() 호출 → 자식 show 실행
- total = 18 + (18 * 2) = 54
- v += 2; total += (v++); show();
- 최종 결과
- parent.total → 54
단계 실행 위치 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
풀이
- main
- data : 배열 객체의 주소를 가짐
- s : 문자열 B
- change(data,s)
- 매개변수 전달
- data : 배열의 주소가 복사되어 전달됨
- s : B 값이 복사되어 전달됨
- 매개변수 전달
- change() 내부 동작
- data[0] = s
- 기존 : data[0] = A
- 변경 : data[0] = B
- s = “Z”
- change 메서드 내부의 지역 변수 s 만 바뀜
- main 의 s 는 B
- data[0] = s
- 출력
- 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
풀이
- main() 시작
- f는 입력값이 2보다 크면 예외를 던지는 함수
- run(f) 호출
- f.apply(3) 실행
- x = 3, x > 2 이므로 throw new Exception() 발생
- 예외 발생 시 catch (Exception e) 블록 실행 → return 7;
- 결과: run(f) → 7
- f.apply(3) 실행
- run((int n) → n+9) 호출
- apply(3) → 3 + 9 = 12
- 예외 없음 → catch 실행되지 않음
- 결과: run((int n) -> n + 9) → 12
- 결과
- 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 |
풀이
- Parent ref = new Child();
- ref의 컴파일 타입은 Parent, 실제 객체 타입은 Child.
- ref.x(2)
- x(int i) 메서드는 오버라이딩 되어 있음.
- 실행 시 실제 객체(Child)의 메서드가 호출됨 → 2 + 3 = 5.
- ref.id()
- id()는 static 메서드이므로 오버라이딩되지 않음.
- 참조 변수 타입(Parent) 기준으로 호출됨 → "P" 반환.
- 출력
- 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
풀이
- 객체 생성
- a.v = 1, b.v = 2, c.v = 3
- 배열 초기화인덱스 값 (참조)
arr[0] → a (v=1) arr[1] → b (v=2) arr[2] → c (v=3) - 교환인덱스 값 (참조)
arr[0] → c (v=3) arr[1] → b (v=2) arr[2] → a (v=1) - BO t = arr[0]; // t → a arr[0] = arr[2]; // arr[0] → c arr[2] = t; // arr[2] → a
- 값 변경
- arr[1].v = arr[0].v;
- arr[1] → b, arr[0] → c
- 따라서 b.v = c.v = 3
- 출력
- a.v = 1
- b.v = 3
- c.v = 3
'정보처리기사' 카테고리의 다른 글
| [정보처리기사 실기 오답노트] - 서버 프로그램 구현 (0) | 2025.11.11 |
|---|---|
| [정보처리기사 실기 오답노트] - 통합 구현 (0) | 2025.11.11 |
| [정보처리기사 실기 오답노트] - 데이터 입출력 구현 (0) | 2025.11.11 |
| [정보처리기사 실기 오답노트] - 요구사항 확인 (0) | 2025.11.11 |
| [정보처리기사 실기 오답노트] - Python (0) | 2025.11.11 |