String 문서의 구현 코드다.

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

import java.util.Arrays;
import java.util.Scanner;

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

    public static void main(String[] args) {
        // 1. 리터럴이 같으면 String 객체 하나를 같이 쓴다 (문서 첫 예시의 위쪽 코드)
        String car1 = "Hyundai";
        String car2 = "KIA";
        String car3 = "KIA";
        check(car2 == car3, "같은 리터럴은 같은 객체");
        check(car1 != car2, "다른 리터럴은 다른 객체");

        // 2. new는 늘 새 객체를 만든다 (문서 첫 예시의 아래쪽 코드)
        String n1 = new String("Hyundai");
        String n2 = new String("KIA");
        String n3 = new String("KIA");
        check(n2 != n3, "new로 만들면 내용이 같아도 다른 객체");
        check(n2 != car2, "new로 만든 것은 리터럴 객체와도 다르다");
        check(n2.equals(n3) && n2.equals(car2), "equals는 글자를 비교한다");
        check(!n1.equals(n2), "글자가 다르면 equals는 false");
        check(n2.intern() == car2, "intern()은 리터럴 쪽 객체를 돌려준다");

        // 3. 실행 중에 만든 문자열은 리터럴과 글자가 같아도 다른 객체다
        String k = "K";
        String joined = k + "IA";
        check(joined.equals("KIA") && joined != car2, "변수로 이어 붙인 문자열");
        String constant = "K" + "IA";      // 리터럴끼리는 컴파일할 때 미리 붙인다
        check(constant == car2, "리터럴끼리 붙인 것은 같은 객체");
        Scanner scanner = new Scanner("KIA\n");
        String typed = scanner.nextLine();
        scanner.close();
        check(typed != car2 && typed.equals(car2), "입력받은 문자열은 == 로 비교하면 틀린다");
        check(!"kia".equals("KIA") && "kia".equalsIgnoreCase("KIA"), "대소문자");

        // 4. 주요 메서드 (문서의 예: "자바 프로그래밍")
        String subject = "자바 프로그래밍";
        check(subject.length() == 8, "길이 8 (빈칸 포함)");
        check(subject.charAt(0) == '자' && subject.charAt(2) == ' ' && subject.charAt(3) == '프', "charAt");
        check(subject.charAt(subject.length() - 1) == '밍', "마지막 글자");
        check(subject.indexOf("프로그래밍") == 3, "indexOf = 3");
        check(subject.indexOf("파이썬") == -1, "없으면 -1");
        check(subject.contains("자바") && !subject.contains("파이썬"), "contains");
        check(subject.substring(3).equals("프로그래밍"), "substring(3)");
        check(subject.substring(0, 2).equals("자바"), "substring(0, 2)");
        check(subject.substring(3, 5).equals("프로"), "substring(3, 5): 끝 번호는 빼고");
        check(subject.substring(8).equals(""), "substring(길이)는 빈 문자열");

        // 5. replace는 새 문자열을 돌려주고 원래 문자열은 그대로다
        String replaced = subject.replace("자바", "Java");
        check(replaced.equals("Java 프로그래밍"), "replace 결과");
        check(subject.equals("자바 프로그래밍"), "원래 문자열은 그대로");
        check(replaced != subject, "다른 객체");
        String up = "java";
        up.toUpperCase();                  // 결과를 받지 않으면 아무 일도 없다
        check(up.equals("java"), "결과를 받지 않은 toUpperCase");
        up = up.toUpperCase();
        check(up.equals("JAVA"), "결과를 다시 넣어야 한다");

        // 6. split
        String board = "번호,제목,내용,글쓴이";
        String[] arr = board.split(",");
        check(arr.length == 4, "네 조각");
        check(Arrays.equals(arr, new String[] {"번호", "제목", "내용", "글쓴이"}), "조각 내용");
        check(arr[3].equals("글쓴이") && !arr[3].equals("성명"), "arr[3]은 글쓴이");

        // 7. 범위를 벗어난 번호
        boolean threw = false;
        try {
            subject.charAt(8);
        } catch (StringIndexOutOfBoundsException e) {
            threw = true;
        }
        check(threw, "charAt(8)은 예외");

        // 8. 카드
        String a = "java";
        String b = "java";
        String c = new String("java");
        String d = c;
        check((a == b) && !(a == c) && a.equals(c) && (c == d), "카드 추적");
        String s = "hello world";
        check(s.substring(s.indexOf("w")).equals("world"), "world 잘라내기");
        check(s.substring(0, s.indexOf(" ")).equals("hello"), "hello 잘라내기");
        check(s.replace("l", "L").equals("heLLo worLd") && s.length() == 11, "replace는 모두 바꾼다");
        check("2026-10-11".split("-")[1].equals("10"), "날짜에서 달 꺼내기");

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