Java 추가 문법의 제한적 포함

정보처리실무 · 프로그래밍 언어·코드 해석

이 페이지의 목차

학습 목표

짧은 코드에서 타입과 호출 결과를 확인할 범위로만 학습한다.

본문

핵심 이론

제네릭 타입 매개변수의 상한과 메서드 본문의 선언 타입을 확인한다. 오버로딩은 컴파일 시 적용 가능한 선언 타입으로 선택되며, 호출 때 전달된 구체 객체의 타입만으로 이미 선택한 오버로드가 바뀌지 않는다.

enum의 values()는 선언 순서의 상수 배열, name()은 선언된 이름, ordinal()은 0부터의 순서다. toString()은 재정의될 수 있어 name()과 항상 같지는 않다.

람다는 하나의 추상 메서드를 갖는 함수형 인터페이스의 구현으로 사용된다. 매개변수와 반환식의 타입을 확인하고, 캡처하는 지역변수는 final 또는 사실상 final이어야 한다.

Runnable.run()을 직접 호출하면 현재 스레드에서 실행한다. Thread.start()는 새 스레드 실행을 시작한다. 동기화·join 등 순서 보장이 없으면 병렬 출력의 하나의 고정 순서를 단정하지 않는다. 고급 제네릭 증명과 동시성 라이브러리 내부는 여기서 확장하지 않는다.

추가 문법도 기본 호출과 배열 규칙으로 읽는다

enum은 이름이 있는 제한된 값들의 집합이다. WAIT·LOAD·RUN·STOP 네 상수가 선언되면 ordinal은 각각 0·1·2·3이다. values()로 얻은 배열에서 인덱스를 선택하고 name()으로 이름을 출력하는 흐름을 일반 배열 문제처럼 계산한다. enum에 필드가 있으면 상수별 필드 값을 함께 적는다.

람다 x -> x+3은 전달받은 x로 계산해서 결과를 돌려주는 간단한 동작이다. 실행 시점은 람다를 만들 때가 아니라 함수형 인터페이스의 메서드를 호출할 때다. 캡처한 배열의 원소는 나중에 바뀔 수 있으므로 두 번 호출했다면 각 호출 시점의 원소 값을 읽는다.

작업추적할 대상
enum 순환이전 ordinal, 이동량, 나머지, 새 상수
람다 호출전달 인수, 캡처한 객체의 현재 값, 반환
Holder<int[]>Holder 객체와 그 안의 배열 참조를 각각 표시
run/start/join현재 스레드 호출인지, 새 실행 시작인지, 완료 대기인지

join 이후에는 대상 스레드가 종료되었으므로 그 완료가 보장된 뒤의 상태를 읽는다. 반대로 별도 순서 보장이 없는 병렬 출력을 하나로 확정하지 않는다. 제네릭의 상한·선언 형식에 따른 오버로드 선택은 함께 확인한다. 스레드 재시작 예외의 명칭 암기는 보충 범위로 구분한다.

풀이 예시

다음 Java 17 프로그램이 표준 출력에 기록하는 내용을 쓰시오. 마지막 줄바꿈의 유무는 답안에서 구별하지 않는다.

JAVA
public class Main {
    enum Phase { WAIT, LOAD, RUN, STOP }
    public static void main(String[] args) {
        Phase p = Phase.LOAD;
        int[] jumps = {2, 3, 1};
        for (int j : jumps)
            p = Phase.values()[(p.ordinal() + j) % Phase.values().length];
        System.out.println(p.name());
    }
}
정답과 풀이 보기

예시 정답

예시·텍스트
STOP

풀이 과정

LOAD의 ordinal은 1이다. 이동 후 인덱스는 (1+2)%4=3, (3+3)%4=2, (2+1)%4=3이다. 3번 열거 값은 STOP이다.

제네릭과 오버로드를 함께 추적하기

제한 없는 T의 상한은 Object이고 T extends Number의 상한은 Number다. 제네릭 메서드 본문에서 오버로드를 고를 때도 이 상한과 선언 형식을 사용한다. 구체적인 Integer나 String을 인수로 전달했다는 이유만으로 본문 호출이 다른 오버로드로 다시 선택되지는 않는다. 오버로딩 선택과 오버라이딩 실행을 분리하여 확인한다.