static 멤버 문서의 구현 코드다.

// 실행: docker run --rm -v "$PWD":/w -w /w eclipse-temurin:21-jdk java 16_java-static_impl.java
// (JDK 21. 파일 이름이 숫자로 시작해 public 클래스를 두지 않는다. 맨 위 클래스의 main이 돈다.)
// 문서 「static 멤버」의 예제 출력과 카드 답을 실제 실행 결과와 비교한다.

class StaticCheck {
    // 문서의 Calculator: 객체를 만들지 않고 클래스 이름으로 쓴다
    static void calculator() {
        double result1 = 10 * 10 * Calculator.pi;
        int result2 = Calculator.plus(10, 5);
        int result3 = Calculator.minus(10, 5);
        System.out.println(result1);
        System.out.println(result2);
        System.out.println(result3);
    }

    // 정적 필드는 클래스에 하나뿐이라 모든 객체가 같이 본다
    static void shared() {
        Scv a = new Scv();
        Scv b = new Scv();
        Scv c = new Scv();
        System.out.println(a.id + " " + b.id + " " + c.id);
        System.out.println(Scv.count);
        Scv none = null;
        System.out.println(none.count);   // 객체가 없어도 된다. 변수의 타입 Scv만 본다
    }

    // 정적 블록은 클래스를 처음 쓸 때 한 번, 적힌 순서대로 돈다
    static void staticBlock() {
        System.out.println("before");
        System.out.println(Table.squares[2]);
        System.out.println(Table.squares[3]);
    }

    // 정적 메서드에서 인스턴스 멤버를 쓰려면 객체부터 만든다
    static void viaObject() {
        System.out.println(Robot.makeAndUse());
    }

    // 카드 C3
    static void card() {
        Counter a = new Counter();
        Counter b = new Counter();
        a.inc();
        a.inc();
        b.inc();
        System.out.println(a.own + " " + b.own + " " + Counter.shared);
    }

    public static void main(String[] args) {
        check("calculator", capture(StaticCheck::calculator), "314.159\n15\n5\n");
        check("shared", capture(StaticCheck::shared), "1 2 3\n3\n3\n");
        check("static block", capture(StaticCheck::staticBlock), "before\nblock 1\nblock 2\n4\n9\n");
        check("via object", capture(StaticCheck::viaObject), "10\n");
        check("card C3", capture(StaticCheck::card), "2 1 3\n");
        System.out.println("ALL CHECKS PASSED");
    }

    static String capture(Runnable r) {
        java.io.PrintStream old = System.out;
        java.io.ByteArrayOutputStream buf = new java.io.ByteArrayOutputStream();
        System.setOut(new java.io.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.print("[" + name + "]\n" + got);
    }
}

class Calculator {
    static double pi = 3.14159;
    static int plus(int x, int y) { return x + y; }
    static int minus(int x, int y) { return x - y; }
}

class Scv {
    static int count = 0;   // 클래스에 하나
    int id;                 // 객체마다 하나

    Scv() {
        count++;
        id = count;
    }
}

class Table {
    static int[] squares;

    static {
        System.out.println("block 1");
        squares = new int[5];
        for (int i = 0; i < squares.length; i++) {
            squares[i] = i * i;
        }
    }

    static {
        System.out.println("block 2");
    }
}

class Robot {
    int field1;

    int method1() { return field1; }

    static int makeAndUse() {
        Robot obj = new Robot();
        obj.field1 = 10;
        return obj.method1();
    }
}

class Counter {
    static int shared;
    int own;

    void inc() {
        shared++;
        own++;
    }
}