다중 구현과 인터페이스 상속 문서의 구현 코드다.

// 다중 구현과 인터페이스 상속
// 실행: docker run --rm -v "$PWD":/w -w /w eclipse-temurin:21-jdk java 27_java-interface-inheritance_impl.java
// 문서(27.다중 구현과 인터페이스 상속.md)에 실은 출력과 카드의 답을 직접 비교한다.
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

class InterfaceInheritanceCheck {
    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(() -> {
            SmartTelevision tv = new SmartTelevision();
            RemoteControl rc = tv;
            Searchable sc = tv;
            rc.turnOn();
            sc.search("java");
            System.out.println(rc == sc);
        }), "Turn on TV\nSearch: java\ntrue\n");

        // 인터페이스 상속: 문서의 InterfaceA, B, C
        check("인터페이스 상속", capture(() -> {
            InterfaceCImpl impl = new InterfaceCImpl();
            InterfaceA ia = impl;
            ia.methodA();
            InterfaceB ib = impl;
            ib.methodB();
            InterfaceC ic = impl;
            ic.methodA();
            ic.methodB();
            ic.methodC();
        }), "methodA\nmethodB\nmethodA\nmethodB\nmethodC\n");

        // 두 인터페이스가 같은 디폴트 메서드를 가지면 구현 클래스가 다시 정의해야 한다
        check("디폴트 메서드 충돌을 푼다", capture(() -> new Robot().hello()), "Walker hello\nTalker hello\nRobot hello\n");

        // 카드 C3
        check("카드 C3", capture(() -> {
            InterfaceC ic = new InterfaceCImpl();
            InterfaceA ia = ic;
            ia.methodA();
            ic.methodC();
            System.out.println(ia instanceof InterfaceB);
        }), "methodA\nmethodC\ntrue\n");

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

interface RemoteControl { void turnOn(); }
interface Searchable { void search(String url); }

class SmartTelevision implements RemoteControl, Searchable {
    @Override
    public void turnOn() { System.out.println("Turn on TV"); }
    @Override
    public void search(String url) { System.out.println("Search: " + url); }
}

interface InterfaceA { void methodA(); }
interface InterfaceB { void methodB(); }
interface InterfaceC extends InterfaceA, InterfaceB { void methodC(); }

class InterfaceCImpl implements InterfaceC {
    public void methodA() { System.out.println("methodA"); }
    public void methodB() { System.out.println("methodB"); }
    public void methodC() { System.out.println("methodC"); }
}

interface Walker { default void hello() { System.out.println("Walker hello"); } }
interface Talker { default void hello() { System.out.println("Talker hello"); } }

class Robot implements Walker, Talker {
    @Override
    public void hello() {
        Walker.super.hello();
        Talker.super.hello();
        System.out.println("Robot hello");
    }
}