디폴트·정적·private 메서드 문서의 구현 코드다.

// 인터페이스의 디폴트·정적·private 메서드
// 실행: docker run --rm -v "$PWD":/w -w /w eclipse-temurin:21-jdk java 26_java-interface-methods_impl.java
// 문서(26.디폴트·정적·private 메서드.md)에 실은 출력과 카드의 답을 직접 비교한다.
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

class InterfaceMethodsCheck {
    static String capture(Runnable r) {
        PrintStream old = System.out;
        ByteArrayOutputStream buf = new ByteArrayOutputStream();
        System.setOut(new PrintStream(buf));
        try { r.run(); } finally { System.setOut(old); }
        return buf.toString();
    }

    static void check(String name, String got, String want) {
        if (!got.equals(want)) throw new AssertionError(name + "\n--- got ---\n" + got + "--- want ---\n" + want);
        System.out.println("ok: " + name);
    }

    public static void main(String[] args) {
        // 디폴트 메서드: 구현 클래스가 아무것도 안 써도 쓸 수 있다
        check("디폴트 메서드를 그대로 쓴다", capture(() -> {
            RemoteControl rc = new Television();
            rc.setMute(true);
            rc.setMute(false);
        }), "Mute on\nVolume 0\nMute off\nVolume 5\n");

        // 디폴트 메서드를 다시 정의한 구현 클래스
        check("디폴트 메서드를 다시 정의한다", capture(() -> {
            RemoteControl rc = new Audio();
            rc.setMute(true);
        }), "Audio mute on\n");

        // 정적 메서드: 객체 없이 인터페이스 이름으로 부른다
        check("정적 메서드", capture(() -> RemoteControl.changeBattery()), "Change battery\n");

        // 문서의 Service 예제
        check("Service.staticMethod1", capture(() -> Service.staticMethod1()), "staticMethod1\nstaticCommon\n");
        check("Service.staticMethod2", capture(() -> Service.staticMethod2()), "staticMethod2\nstaticCommon\n");
        Service s = new ServiceImpl();
        check("defaultMethod1", capture(() -> s.defaultMethod1()), "defaultMethod1\ndefaultCommon\n");
        check("defaultMethod2", capture(() -> s.defaultMethod2()), "defaultMethod2\ndefaultCommon\nstaticCommon\n");

        // 카드 C3
        check("카드 C3", capture(() -> {
            Service x = new ServiceImpl();
            x.defaultMethod2();
            Service.staticMethod1();
        }), "defaultMethod2\ndefaultCommon\nstaticCommon\nstaticMethod1\nstaticCommon\n");

        System.out.println("ALL CHECKS PASSED");
    }
}

interface RemoteControl {
    int MAX_VOLUME = 10;
    int MIN_VOLUME = 0;

    void setVolume(int volume);                 // 추상 메서드

    default void setMute(boolean mute) {        // 디폴트 메서드
        if (mute) {
            System.out.println("Mute on");
            setVolume(MIN_VOLUME);              // 상수를 읽고 추상 메서드를 부른다
        } else {
            System.out.println("Mute off");
            setVolume(MAX_VOLUME / 2);
        }
    }

    static void changeBattery() {               // 정적 메서드
        System.out.println("Change battery");
    }
}

class Television implements RemoteControl {
    @Override
    public void setVolume(int volume) { System.out.println("Volume " + volume); }
}

class Audio implements RemoteControl {
    @Override
    public void setVolume(int volume) { System.out.println("Audio volume " + volume); }
    @Override
    public void setMute(boolean mute) { System.out.println(mute ? "Audio mute on" : "Audio mute off"); }
}

interface Service {
    default void defaultMethod1() {
        System.out.println("defaultMethod1");
        defaultCommon();
    }

    default void defaultMethod2() {
        System.out.println("defaultMethod2");
        defaultCommon();
        staticCommon();
    }

    private void defaultCommon() {
        System.out.println("defaultCommon");
    }

    static void staticMethod1() {
        System.out.println("staticMethod1");
        staticCommon();
    }

    static void staticMethod2() {
        System.out.println("staticMethod2");
        staticCommon();
    }

    private static void staticCommon() {
        System.out.println("staticCommon");
    }
}

class ServiceImpl implements Service { }