배열 문서의 구현 코드다.

// 실행: docker run --rm -v "$PWD":/w -w /w eclipse-temurin:21-jdk java 10_java-array_impl.java
// 배열 문서의 출력과 값을 확인한다.

import java.util.Arrays;

class ArrayImpl {
    static void check(boolean ok, String what) {
        if (!ok) throw new AssertionError(what);
    }

    // 문서의 "java Sum 10 20": 실행할 때 준 글자들이 String[] args로 들어온다
    static int sumArgs(String[] args) {
        int sum = 0;
        for (String arg : args) {
            sum += Integer.parseInt(arg);
        }
        return sum;
    }

    public static void main(String[] args) {
        // 1. 선언하는 두 모양
        int[] numbers1;
        int numbers2[];
        numbers1 = null;                   // 가리킬 배열이 없으면 null
        check(numbers1 == null, "null로 둘 수 있다");

        // 2. 값 목록으로 만들기
        int[] score = {83, 90, 87, 93, 78};
        check(score.length == 5, "길이 5");
        check(score[0] == 83 && score[4] == 78, "첫 칸과 마지막 칸");
        check(score[score.length - 1] == 78, "마지막 칸은 length - 1");
        score[1] = 95;
        check(score[1] == 95, "칸에 값 넣기");
        // 선언과 따로 넣을 때는 new 타입[] 을 붙인다
        numbers2 = new int[] {1, 2, 3};
        check(numbers2.length == 3, "new int[]{...}");

        // 3. new로 만들면 기본값으로 채워진다
        check((new byte[1])[0] == 0 && (new short[1])[0] == 0 && (new int[1])[0] == 0 && (new long[1])[0] == 0L, "정수 0");
        check((new char[1])[0] == '\u0000', "char \\u0000");
        check((new float[1])[0] == 0.0f && (new double[1])[0] == 0.0, "실수 0.0");
        check((new boolean[1])[0] == false, "boolean false");
        check((new String[1])[0] == null, "참조 타입 null");
        int[] empty = new int[3];
        check(Arrays.toString(empty).equals("[0, 0, 0]"), "new int[3]");

        // 4. 범위를 벗어난 번호
        boolean threw = false;
        String msg = "";
        try {
            int v = score[5];
        } catch (ArrayIndexOutOfBoundsException e) {
            threw = true;
            msg = e.getMessage();
        }
        check(threw && msg.equals("Index 5 out of bounds for length 5"), "범위 밖: " + msg);

        // 5. 2차원 배열: 배열의 칸마다 배열의 주소가 들어 있다
        int[][] scores = {
            {80, 92, 96},
            {76, 88}
        };
        check(scores.length == 2, "반의 수 2");
        check(scores[0].length == 3 && scores[1].length == 2, "반마다 길이가 다를 수 있다");
        check(scores[0][2] == 96 && scores[1][0] == 76, "칸 읽기");
        int[][] grid = new int[2][3];
        check(Arrays.deepToString(grid).equals("[[0, 0, 0], [0, 0, 0]]"), "new int[2][3]");
        int[][] jag = new int[2][];
        check(jag[0] == null && jag[1] == null, "안쪽을 안 만들면 null");
        jag[0] = new int[3];
        jag[1] = new int[1];
        check(jag[0].length == 3 && jag[1].length == 1, "안쪽을 따로 만들기");
        int total = 0;
        for (int i = 0; i < scores.length; i++) {
            for (int j = 0; j < scores[i].length; j++) {
                total += scores[i][j];
            }
        }
        check(total == 432, "모든 점수의 합 432");

        // 6. 참조 타입 배열 (문서의 strArray)
        String[] strArray = new String[3];
        check(strArray[0] == null, "처음에는 null");
        strArray[0] = "Java";
        strArray[1] = "C++";
        strArray[2] = "C#";
        check(Arrays.toString(strArray).equals("[Java, C++, C#]"), "strArray");
        String[] langs = {"Java", "Java", new String("Java")};
        check(langs[0] == langs[1] && langs[0] != langs[2] && langs[0].equals(langs[2]), "칸에는 주소가 들어 있다");

        // 7. 복사: 대입은 주소만 복사한다
        int[] src = {1, 2, 3};
        int[] alias = src;
        alias[0] = 100;
        check(src[0] == 100, "대입은 같은 배열을 가리킨다");
        src[0] = 1;
        // (a) for로 한 칸씩
        int[] c1 = new int[5];
        for (int i = 0; i < src.length; i++) {
            c1[i] = src[i];
        }
        check(Arrays.toString(c1).equals("[1, 2, 3, 0, 0]"), "for 복사");
        // (b) System.arraycopy(원본, 원본 시작, 대상, 대상 시작, 개수)
        int[] c2 = new int[5];
        System.arraycopy(src, 0, c2, 1, 3);
        check(Arrays.toString(c2).equals("[0, 1, 2, 3, 0]"), "arraycopy");
        // (c) Arrays.copyOf(원본, 새 길이)
        int[] c3 = Arrays.copyOf(src, 5);
        check(Arrays.toString(c3).equals("[1, 2, 3, 0, 0]"), "copyOf");
        c3[0] = -1;
        check(src[0] == 1, "복사본을 고쳐도 원본은 그대로");
        // 참조 타입 배열과 2차원 배열은 주소만 복사된다
        int[][] m = {{1, 2}, {3, 4}};
        int[][] m2 = Arrays.copyOf(m, 2);
        m2[0][0] = 99;
        check(m[0][0] == 99 && m != m2 && m[0] == m2[0], "2차원 배열의 얕은 복사");

        // 8. 향상된 for
        int sum = 0;
        for (int s : score) {
            sum += s;
        }
        check(sum == 83 + 95 + 87 + 93 + 78, "향상된 for의 합 436");
        check(sum == 436, "436");
        int[] twice = {1, 2, 3};
        for (int v : twice) {
            v = v * 2;                     // v는 복사본이다. 배열은 바뀌지 않는다
        }
        check(Arrays.toString(twice).equals("[1, 2, 3]"), "향상된 for로는 칸을 못 고친다");
        for (int i = 0; i < twice.length; i++) {
            twice[i] = twice[i] * 2;
        }
        check(Arrays.toString(twice).equals("[2, 4, 6]"), "번호로 돌아야 고친다");
        int rowSum = 0;
        for (int[] row : scores) {
            for (int v : row) {
                rowSum += v;
            }
        }
        check(rowSum == 432, "2차원 향상된 for");

        // 9. main의 String[] args
        check(sumArgs(new String[] {"10", "20"}) == 30, "java Sum 10 20 -> 30");
        check(args.length == 0, "인자 없이 실행하면 길이 0 배열 (null이 아니다)");

        // 10. 카드
        int[] a = {3, 1, 4, 1, 5};
        int max = a[0];
        for (int i = 1; i < a.length; i++) {
            if (a[i] > max) max = a[i];
        }
        check(max == 5, "최댓값 5");
        int[][] t = new int[3][];
        t[0] = new int[] {1};
        t[1] = new int[] {1, 2};
        check(t.length == 3 && t[1].length == 2 && t[2] == null, "카드 추적");

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