This page needs a recent browser (with SharedArrayBuffer support). Please update Chrome, Edge, Firefox or Safari to the latest version. · 이 페이지는 최신 브라우저(SharedArrayBuffer 지원)가 필요합니다. Chrome, Edge, Firefox 또는 Safari를 최신 버전으로 업데이트해 주세요.
Every Java program lives inside a class 类. It starts at a method 方法 named main. System.out.println(...) prints a line; System.out.print(...) prints with no new line.
Java is compiled 编译: the compiler 编译器 checks the whole program, then it runs.
Every statement 语句 ends with a semicolon ;.
한국어
모든 Java 프로그램은 클래스 내부에 존재합니다. 프로그램은 main라는 메서드에서 시작됩니다. System.out.println(...)는 줄을 출력하고; System.out.print(...)는 줄바꿈 없이 출력합니다.
public class Main {
public static void main(String[] args) {
System.out.println("Hello, world!");
System.out.println("I am learning Java.");
}
}
Java는 컴파일됩니다: 컴파일러가 전체 프로그램을 검사한 후 실행합니다.
모든 문장은 세미콜론 ;로 끝납니다.
Java 프로그램은 클래스 안에 있으며 main에서 시작함
1.2
변수 & 원시 데이터 타입
English
A variable 变量 must declare 声明 its type. Common primitive types 基本类型: int (whole number), double (decimal), boolean (true/false), char (one letter).
한국어
변수는 반드시 데이터 타입을 선언해야 합니다. 일반적인 원시 데이터 타입: int(정수), double(소수점 숫자), boolean(true/false), char(단일 문자).
public class Main {
public static void main(String[] args) {
int age = 17;
double price = 9.99;
boolean passed = true;
System.out.println(age + " " + price + " " + passed);
}
}
1.3
Comments & style
English
A comment 注释 is // (one line) or /* ... */ (a block). Indent the code inside braces { }. Class names start Capitalised; variables and methods use camelCase 驼峰命名 (lowercase first).
Common mistakes
Every statement ends with a semicolon ;.
main must be exactly public static void main(String[] args).
Java arithmetic 算术 uses + - * / and % (remainder). With two ints, / is integer division 整数除法 — it drops the decimal. +=, -=, and ++ are shortcuts.
한국어
Java arithmetic 算术 uses + - * / and % (remainder). With two ints, / is integer division 整数除法 — it drops the decimal. +=, -=, and ++ are shortcuts.
public class Main {
public static void main(String[] args) {
int a = 7, b = 2;
System.out.println(a / b); // 3 (integer division)
System.out.println(a % b); // 1
double x = 7.0 / 2; // 3.5 (one side is double)
System.out.println(x);
}
}
int/int truncates; involve a double for a real quotient
2.2
Using objects: String, Math, wrappers
English
Some values are objects 对象 with methods. String has .length(), .substring(), .toUpperCase(). Math has Math.max, Math.sqrt, Math.pow. Wrapper classes 包装类 (Integer, Double) wrap a primitive — e.g. Integer.parseInt("42").
Math.random() returns a random 随机double from 0.0 up to (but not including) 1.0. Scale it and cast to get whole numbers — this is the AP idiom:
Integer.MAX_VALUE (2147483647) and Integer.MIN_VALUE are the limits of int; going past them wraps around (an overflow).
An object variable that points at no object holds null; calling a method on it throws a NullPointerException.
한국어
Some values are objects 对象 with methods. String has .length(), .substring(), .toUpperCase(). Math has Math.max, Math.sqrt, Math.pow. Wrapper classes 包装类 (Integer, Double) wrap a primitive — e.g. Integer.parseInt("42").
public class Main {
public static void main(String[] args) {
String s = "Hello";
System.out.println(s.length()); // 5
System.out.println(s.toUpperCase()); // HELLO
System.out.println(Math.max(3, 9)); // 9
System.out.println(Integer.parseInt("42") + 1); // 43
}
}
Math.random() returns a random 随机 double from 0.0 up to (but not including) 1.0. Scale it and cast to get whole numbers — this is the AP idiom:
public class Main {
public static void main(String[] args) {
// a random whole number from 1 to 6 (a dice roll)
int roll = (int) (Math.random() * 6) + 1;
System.out.println(roll >= 1 && roll <= 6); // true
}
}
Integer.MAX_VALUE (2147483647) and Integer.MIN_VALUE are the limits of int; going past them wraps around (an overflow).
An object variable that points at no object holds null; calling a method on it throws a NullPointerException.
2.3
Casting & type conversion
English
A cast 强制转换 changes a value's type. (int) drops the decimal; (double) avoids integer division when you need an exact result.
Common mistakes
Integer division: 5 / 2 is 2, not 2.5. Cast first: (double) 5 / 2.
Compare Strings (and other objects) with .equals(), not ==.
== on two objects tests whether they are the SAME object, not whether they look equal.
한국어
A cast 强制转换 changes a value's type. (int) drops the decimal; (double) avoids integer division when you need an exact result.
public class Main {
public static void main(String[] args) {
double pi = 3.99;
System.out.println((int) pi); // 3
int total = 7, n = 2;
System.out.println((double) total / n); // 3.5
}
}
Common mistakes
Integer division: 5 / 2 is 2, not 2.5. Cast first: (double) 5 / 2.
Compare Strings (and other objects) with .equals(), not ==.
== on two objects tests whether they are the SAME object, not whether they look equal.
if runs a block when a condition 条件 is true; else if and else add more cases. The condition goes in ( ), the block in { }.
한국어
if는 조건이 참일 때 블록을 실행하며, else if과 else은 더 많은 경우를 추가합니다. 조건은 ( )에, 블록은 { }에 넣습니다.
public class Main {
public static void main(String[] args) {
int score = 72;
if (score >= 80) {
System.out.println("A");
} else if (score >= 60) {
System.out.println("B");
} else {
System.out.println("fail");
}
}
}
if는 참인 분기를 선택; else는 거짓 분기를 선택합니다
3.2
논리 연산자 및 비교
English
Compare with ==, !=, <, >, <=, >= — a comparison 比较 gives a boolean. Combine with && (and), || (or), ! (not) — the logical operators 逻辑运算符. For Strings, use .equals(...), not==.
한국어
==, !=, <, >, <=, >=로 비교하여 boolean를 얻습니다. 논리 연산자인 &&(and), ||(or), !(not)로 결합하십시오. String의 경우, .equals(...)을 사용하고 반드시==을 사용하지 마십시오.
public class Main {
public static void main(String[] args) {
int age = 16;
boolean member = true;
System.out.println(age >= 18 && member); // false
String a = "hi";
System.out.println(a.equals("hi")); // true
}
}
3.3
switch
English
switch chooses among many fixed values. Each case ends with break; default is the fallback.
Common mistakes
A condition must be a boolean; if (x = 5) does not compile (use ==).
Each switch case needs a break;, or control falls through to the next case.
&& and || are the logical operators; & and | are bitwise.
한국어
switch는 여러 고정된 값 중 하나를 선택합니다. 각 case은 break으로 끝납니다; default은 기본값(fallback)입니다.
public class Main {
public static void main(String[] args) {
int day = 3;
switch (day) {
case 1: System.out.println("Mon"); break;
case 3: System.out.println("Wed"); break;
default: System.out.println("other");
}
}
}
Common mistakes
조건은 반드시 boolean여야 하며, if (x = 5)은 컴파일되지 않습니다(==을 사용하십시오).
각 switch case에는 break;이 있어야 하며, 그렇지 않으면 제어가 다음 case로Fall through됩니다.
A while loop repeats while a condition is true. Change something inside, or it loops forever.
한국어
while 루프는 조건이 참인 동안 반복됩니다. 내부에서 값을 변경하지 않으면 무한 루프가 됩니다.
public class Main {
public static void main(String[] args) {
int n = 1;
while (n <= 3) {
System.out.println(n);
n++;
}
}
}
while checks the condition before each pass of the body
4.2
for 루프
English
A for loop packs the start, the condition, and the step into one line. Best when you know the count.
한국어
for 루프는 시작값, 조건, 단계값을 한 줄에 묶습니다. 반복 횟수가 명확할 때 가장 적합합니다.
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
System.out.print(i + " ");
}
System.out.println(); // 0 1 2 3 4
}
}
4.3
누적 (Accumulation)
English
The accumulator 累加器 pattern: start a variable before the loop, then update it each turn.
한국어
누적 패턴: 루프 전에 변수를 초기화한 뒤, 매 반복마다 값을 업데이트합니다.
public class Main {
public static void main(String[] args) {
int total = 0;
for (int i = 1; i <= 5; i++) {
total += i;
}
System.out.println(total); // 15
}
}
4.4
중첩 루프
English
A loop inside a loop is a nested loop 嵌套循环. The inner loop runs fully on each turn of the outer one.
Common mistakes
for (int i = 0; i < n; i++) runs n times (0 to n - 1); using <= runs one extra.
Do not put a semicolon right after for (...) or while (...) — it makes an empty loop.
Declare the counter in the for header so its scope ends with the loop.
한국어
루프 안에 다른 루프가 있는 것을 중첩 루프라고 합니다. 외부 루프의 각 반복 시 내부 루프가 완전히 실행됩니다.
public class Main {
public static void main(String[] args) {
for (int r = 0; r < 3; r++) {
for (int c = 0; c < 3; c++) {
System.out.print("*");
}
System.out.println();
}
}
}
Common mistakes
for (int i = 0; i < n; i++)는 n번 실행됩니다(0부터 n - 1까지); <=를 사용하면 한 번 더 추가 실행됩니다.
for (...) 또는 while (...) 바로 뒤에 세미콜론을 두면 안 됩니다—빈 루프가 생성되기 때문입니다.
A String 字符串 is text. Useful methods: .length(), .charAt(i), .substring(a, b), .indexOf(x), .toUpperCase(), .equals(...). Strings are immutable 不可变 — each method returns a new String.
The methods you will use every day:
Method
Meaning
Example → result
.length()
how many characters
"Hi".length() → 2
.charAt(i)
one character
"Hi".charAt(0) → H
.substring(a, b)
part, stops before b
"Python".substring(0, 3) → Pyt
.substring(a)
from a to the end
"Python".substring(3) → hon
.indexOf(x)
first position, -1 if absent
"banana".indexOf("na") → 2
.equals(s)
same text?
"hi".equals("hi") → true
.compareTo(s)
order: negative / 0 / positive
"apple".compareTo("banana") → negative
compareTo puts Strings in dictionary order — the AP exam uses it for sorting questions:
한국어
String는 텍스트입니다. 유용한 메서드: .length(), .charAt(i), .substring(a, b), .indexOf(x), .toUpperCase(), .equals(...). String은 불변이며, 각 메서드는 새로운 String을 반환합니다.
public class Main {
public static void main(String[] args) {
String s = "Python";
System.out.println(s.length()); // 6
System.out.println(s.charAt(0)); // P
System.out.println(s.substring(0, 3)); // Pyt
System.out.println(s.toUpperCase()); // PYTHON
}
}
매일 사용할 메서드들:
메서드
의미
예시 → 결과
.length()
문자 수
"Hi".length() → 2
.charAt(i)
특정 인덱스의 한 문자
"Hi".charAt(0) → H
.substring(a, b)
일부 추출, b 전까지 (포함 안 함)
"Python".substring(0, 3) → Pyt
.substring(a)
a부터 끝까지
"Python".substring(3) → hon
.indexOf(x)
첫 번째 위치, 없으면 -1
"banana".indexOf("na") → 2
.equals(s)
같은 텍스트?
"hi".equals("hi") → true
.compareTo(s)
순서: 음수 / 0 / 양수
"apple".compareTo("banana") → 음수
compareTo은 문자열을 사전 순서로 정렬합니다 — AP 시험에서는 문제 정렬에 이 방법을 사용합니다:
public class Main {
public static void main(String[] args) {
String a = "apple", b = "banana";
System.out.println(a.compareTo(b) < 0); // true (apple comes first)
System.out.println(a.compareTo("apple")); // 0 (equal)
}
}
핵심 String 메소드: length, charAt, substring, equals
5.2
문자열 생성 및 순회
English
Join strings with + (concatenation 拼接). Visit each character with a loop and .charAt(i).
When you build a long String in a loop, StringBuilder is much faster: append the pieces, then call .toString() once.
Common mistakes
Strings are immutable: s.toUpperCase() returns a new String, so store the result.
Read a character with s.charAt(i); the length is s.length() (a method, with ()).
Building a String with += in a big loop is slow; use a StringBuilder.
한국어
+(연결)으로 문자열을 합치세요. 루프와 .charAt(i)를 사용하여 각 문자를 방문하세요.
public class Main {
public static void main(String[] args) {
String word = "banana";
int count = 0;
for (int i = 0; i < word.length(); i++) {
if (word.charAt(i) == 'a') count++;
}
System.out.println(count); // 3
}
}
루프에서 긴 문자열을 만들 때, StringBuilder이 훨씬 빠릅니다: 조각들을 append한 후, .toString()를 한 번만 호출하세요.
public class Main {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 5; i++) {
sb.append(i).append(" ");
}
System.out.println(sb.toString().trim()); // 1 2 3 4 5
}
}
Common mistakes
문자열은 불변(immutable)입니다: s.toUpperCase()은 새로운 문자열을 반환하므로 결과를 저장해야 합니다.
s.charAt(i)으로 문자를 읽으세요; 길이는 s.length()입니다(()가 있는 메소드).
큰 루프에서 +=으로 문자열을 만드는 것은 느립니다; StringBuilder을 사용하세요.
An array 数组 holds a fixed number of values of one type. Index from 0, and get the size with .length.
한국어
An array 数组 holds a fixed number of values of one type. Index from 0, and get the size with .length.
public class Main {
public static void main(String[] args) {
int[] scores = {88, 71, 95};
System.out.println(scores[0]); // 88
System.out.println(scores.length); // 3
scores[1] = 100;
System.out.println(scores[1]); // 100
}
}
A primitive holds its value; an array variable holds a reference to the array object
6.2
Array algorithms
English
Walk the array with a loop to find a max, a total, a count, or to search 查找. A for-each loop (for (int x : a)) reads each value in turn.
한국어
Walk the array with a loop to find a max, a total, a count, or to search 查找. A for-each loop (for (int x : a)) reads each value in turn.
public class Main {
public static void main(String[] args) {
int[] a = {3, 9, 2, 7};
int max = a[0], total = 0;
for (int x : a) {
if (x > max) max = x;
total += x;
}
System.out.println(max + " " + total); // 9 21
}
}
6.3
2-D arrays
English
A 2-D array 二维数组 is a grid 网格 of rows and columns: grid[row][col].
Common mistakes
An array's size is a.length (no brackets, no ()), and it is fixed when created.
Valid indexes are 0 to a.length - 1; a[a.length] throws ArrayIndexOutOfBoundsException.
A new int[5] is filled with zeros, not left empty.
한국어
A 2-D array 二维数组 is a grid 网格 of rows and columns: grid[row][col].
public class Main {
public static void main(String[] args) {
int[][] grid = {{1, 2, 3}, {4, 5, 6}};
System.out.println(grid[1][2]); // 6
for (int[] row : grid) {
for (int v : row) System.out.print(v + " ");
}
System.out.println(); // 1 2 3 4 5 6
}
}
Common mistakes
An array's size is a.length (no brackets, no ()), and it is fixed when created.
Valid indexes are 0 to a.length - 1; a[a.length] throws ArrayIndexOutOfBoundsException.
A new int[5] is filled with zeros, not left empty.
An ArrayList is a resizable 可变大小 list — it grows and shrinks as you add or remove items. It stores objects, so use a wrapper 包装类 type like Integer (not int). The <Integer> part is a generic 泛型 type. Key methods: .add(x), .get(i), .set(i, x), .size(), .remove(i).
한국어
ArrayList은 확장 가능한 목록으로, 항목을 추가하거나 제거할 때 커지고 작아집니다. 객체를 저장하므로 Integer 같은(wrapper type)을 사용해야 합니다(int가 아님). <Integer>는 제네릭 타입입니다. 주요 메서드: .add(x), .get(i), .set(i, x), .size(), .remove(i).
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> nums = new ArrayList<Integer>();
nums.add(10);
nums.add(20);
nums.add(30);
System.out.println(nums.size()); // 3
System.out.println(nums.get(1)); // 20
nums.set(0, 99);
System.out.println(nums); // [99, 20, 30]
}
}
ArrayList: 확장 가능한 목록에서의 add, get, size
7.2
ArrayList 알고리즘 및 remove 버그
English
.remove(i) shifts 移动 every later element one place left. If you remove while counting iup, you skip the next element. Fix: loop backwards, or don't increment i after a remove.
Common mistakes
ArrayList uses .size(), .get(i) and .add(...) — not the [] you use on arrays.
Removing items while looping forward by index skips the next item (the remove bug). Loop backwards, or use an iterator.
Store objects, not primitives: use ArrayList<Integer>, and Java auto-boxes int values.
한국어
.remove(i)는 이후 모든 요소를 한 자리 왼쪽으로 밀어냅니다. i로 세어 가며 제거하면 다음 요소를 건너뜁니다. 수정 방법: 역순으로 루프를 돌리거나, 제거 후 i를 증가시키지 마십시오.
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> nums = new ArrayList<Integer>();
for (int n : new int[]{4, 7, 4, 9, 4}) nums.add(n);
// Remove every 4 — loop backwards so removals don't skip items.
for (int i = nums.size() - 1; i >= 0; i--) {
if (nums.get(i) == 4) nums.remove(i);
}
System.out.println(nums); // [7, 9]
}
}
Common mistakes
ArrayList는 .size(), .get(i), .add(...)을 사용하며, 배열에서 사용하는 []가 아닙니다.
인덱스로 전진하는 루프 중 항목을 제거하면 다음 항목을 건너뜁니다(remove 버그). 역순으로 루프를 도는지, 이터레이터를 사용하십시오.
원시형(primitives) 대신 객체를 저장합니다: ArrayList<Integer>을 사용하고, Java가 int 값을 자동 박싱(auto-boxing)합니다.
A class 类 is a blueprint for objects. Its fields 字段 store data, its constructor 构造方法 sets up a new object, and its methods 方法 are the actions. this.name means "this object's name". Create an object with new.
A static member belongs to the class itself, not to any one object. Call a static method on the class name — like Math.max — and a static field is shared by every object:
한국어
클래스는 객체의 청사진입니다. 필드는 데이터를 저장하고, 컨스트럭터는 새 객체를 설정하며, 메서드는 동작입니다. this.name는 "이 객체의 name"를 의미합니다. new를 사용하여 객체를 생성합니다.
public class Main {
public static void main(String[] args) {
Dog d = new Dog("Rex", 3);
System.out.println(d.describe()); // Rex is 3 years old
d.haveBirthday();
System.out.println(d.describe()); // Rex is 4 years old
}
}
class Dog {
private String name;
private int age;
public Dog(String name, int age) { // constructor
this.name = name;
this.age = age;
}
public String describe() {
return name + " is " + age + " years old";
}
public void haveBirthday() {
age++;
}
}
static 멤버는 특정 객체가 아닌 클래스 자체에 속합니다. 클래스명 위에 정적 메서드를 호출합니다—Math.max와 같이—and 정적 필드는 모든 객체와 공유됩니다:
public class Main {
public static void main(String[] args) {
System.out.println(Counter.made()); // 0
new Counter();
new Counter();
System.out.println(Counter.made()); // 2
}
}
class Counter {
private static int count = 0; // shared by ALL Counter objects
public Counter() { count++; }
public static int made() { // called on the class: Counter.made()
return count;
}
}
필드는 상태를 저장; 컨스트럭터는 구축; 메서드는 작동
8.2
캡슐화
English
Encapsulation 封装 means hiding data behind methods. Mark fields private so outside code can't touch them directly; expose an accessor 访问方法 (getter) to read, and a method to change them safely. The method can guard the data — here a deposit must be positive.
Common mistakes
A constructor has the class name and no return type (not even void).
Use this.field to tell a field apart from a parameter with the same name.
Make fields private and reach them through getter/setter methods (encapsulation).
한국어
엔캡슐(encapsulation)은 메서드 뒤에서 데이터를 숨기는 것을 의미합니다. 필드를 private로 표시하여 외부 코드가 직접 접근하지 못하게 하고, 읽기용 어세서(getter)를 공개하며, 안전하게 변경하기 위한 메서드를 제공합니다. 메서드로 데이터를 보호(guard) 할 수 있습니다—예를 들어 입금(deposit)은 양수여야 함.
public class Main {
public static void main(String[] args) {
Account a = new Account(100);
a.deposit(50);
a.deposit(-999); // rejected by the guard
System.out.println(a.getBalance()); // 150
}
}
class Account {
private int balance; // hidden from outside
public Account(int start) {
balance = start;
}
public void deposit(int amount) {
if (amount > 0) balance += amount; // guard keeps balance valid
}
public int getBalance() { // accessor (getter)
return balance;
}
}
Common mistakes
컨스트럭터는 클래스명과 반환 유형이 없습니다(void도 포함).
동일한 이름의 매개변수와 구별하려면 this.field를 사용합니다.
필드를 private로 만들고 getter/setter 메서드를 통해 접근하십시오(엔캡슐).
Inheritance 继承 lets a subclass 子类 reuse a superclass 父类. Write class Cat extends Animal and Cat gets Animal's fields and methods for free. Call the parent constructor with super(...).
한국어
상속은 서브클래스가 초기(superclass)의 기능을 재사용할 수 있게 합니다. class Cat extends Animal를 작성하면 Cat이 Animal의 필드와 메서드를 무료로 얻습니다. super(...)를 사용하여 부모 컨스트럭터를 호출합니다.
public class Main {
public static void main(String[] args) {
Cat c = new Cat("Milo");
c.eat(); // Milo is eating (inherited from Animal)
c.speak(); // Meow (Cat's own method)
}
}
class Animal {
protected String name;
public Animal(String name) { this.name = name; }
public void eat() { System.out.println(name + " is eating"); }
}
class Cat extends Animal {
public Cat(String name) { super(name); } // call Animal's constructor
public void speak() { System.out.println("Meow"); }
}
Cat과 Dog가 Animal을 확장: 구성원을 상속하고 자체적인 것들을 추가
9.2
다형성(Polymorphism) 및 toString
English
A subclass can override 重写 a method to replace the parent's version. Polymorphism 多态 means a Shape variable can hold any subtype, and Java picks the right toString at run time. System.out.println(obj) automatically calls obj.toString().
Common mistakes
An overriding method must match the signature exactly; add @Override so the compiler catches slips.
super(...) must be the first line of a subclass constructor.
A subclass object IS-A superclass object, but not the other way round.
한국어
서브클래스는 메서드를 오버라이딩하여 부모의 버전을 대체할 수 있습니다. 다형성은 Shape 변수가 어떤 하위 타입(h subtype)을든 가질 수 있음을 의미하며, Java가 실행 시간(run time)에 올바른 toString을 선택합니다. System.out.println(obj)는 자동으로 obj.toString()를 호출합니다.
public class Main {
public static void main(String[] args) {
Shape[] shapes = { new Circle(2), new Square(3) };
for (Shape s : shapes) {
System.out.println(s); // each calls its own toString
}
}
}
class Shape {
public String toString() { return "a shape"; }
}
class Circle extends Shape {
private int r;
public Circle(int r) { this.r = r; }
public String toString() { return "Circle r=" + r; } // override
}
class Square extends Shape {
private int side;
public Square(int side) { this.side = side; }
public String toString() { return "Square side=" + side; } // override
}
Common mistakes
오버라이딩 메서드는 서명(signature)과 정확히 일치해야 하며, @Override를 추가하여 컴파일러가 실수를 감지하도록 합니다.
Recursion 递归 is a method that calls itself. Every recursion needs a base case 基准情形 (when to stop) and a recursive call 递归调用 that moves toward it. Without a base case it never stops and crashes with a stack overflow.
Trace it: factorial(5) waits for factorial(4), which waits for factorial(3)… down to factorial(1) returning 1. Then the answers multiply back up: 1 → 2 → 6 → 24 → 120.
Recursion also works on Strings — peel off one character each call:
Merge sort 归并排序 is the recursive sort on the AP exam: split the array in half, sort each half recursively, then merge 合并 the two sorted halves. It runs in O(n log n) — far faster than the O(n²) sorts on big arrays.
Common mistakes
Recursion needs a base case, or it throws StackOverflowError.
Each recursive call must move CLOSER to the base case.
Trace a small example by hand to check the recursion returns the right value.
In merge sort, the merge step does the real work; the recursion only splits the array.
한국어
Recursion 递归 is a method that calls itself. Every recursion needs a base case 基准情形 (when to stop) and a recursive call 递归调用 that moves toward it. Without a base case it never stops and crashes with a stack overflow.
The call stack for factorial(3): each call waits, then returns in reverse order
public class Main {
public static void main(String[] args) {
System.out.println(factorial(5)); // 120
}
public static int factorial(int n) {
if (n <= 1) return 1; // base case
return n * factorial(n - 1); // recursive call: n * (n-1)!
}
}
Trace it: factorial(5) waits for factorial(4), which waits for factorial(3)… down to factorial(1) returning 1. Then the answers multiply back up: 1 → 2 → 6 → 24 → 120.
Recursion also works on Strings — peel off one character each call:
public class Main {
public static void main(String[] args) {
System.out.println(reverse("PYTHON")); // NOHTYP
}
static String reverse(String s) {
if (s.length() <= 1) return s; // base case
return reverse(s.substring(1)) + s.charAt(0);
}
}
Merge sort 归并排序 is the recursive sort on the AP exam: split the array in half, sort each half recursively, then merge 合并 the two sorted halves. It runs in O(n log n) — far faster than the O(n²) sorts on big arrays.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] a = {5, 2, 9, 1, 7, 3};
mergeSort(a, 0, a.length - 1);
System.out.println(Arrays.toString(a)); // [1, 2, 3, 5, 7, 9]
}
static void mergeSort(int[] a, int lo, int hi) {
if (lo >= hi) return; // base case: one element
int mid = (lo + hi) / 2;
mergeSort(a, lo, mid); // sort the left half
mergeSort(a, mid + 1, hi); // sort the right half
merge(a, lo, mid, hi); // merge the two halves
}
static void merge(int[] a, int lo, int mid, int hi) {
int[] tmp = new int[hi - lo + 1];
int i = lo, j = mid + 1, k = 0;
while (i <= mid && j <= hi) {
if (a[i] <= a[j]) tmp[k++] = a[i++];
else tmp[k++] = a[j++];
}
while (i <= mid) tmp[k++] = a[i++];
while (j <= hi) tmp[k++] = a[j++];
for (k = 0; k < tmp.length; k++) a[lo + k] = tmp[k];
}
}
Common mistakes
Recursion needs a base case, or it throws StackOverflowError.
Each recursive call must move CLOSER to the base case.
Trace a small example by hand to check the recursion returns the right value.
In merge sort, the merge step does the real work; the recursion only splits the array.
Linear search 线性查找 checks every element — works on any array. Binary search 二分查找 is much faster but needs a sorted 已排序 array: it looks at the middle, then throws away half each step. Both return the index, or -1 if not found.
한국어
선형 검색(linear search)은 모든 요소를 확인합니다—모든 배열에서 작동합니다. 이진 검색(binary search)은 훨씬 빠르지만 정렬된 배열이 필요합니다: 중간을 보고 매 단계마다 절반을 폐기합니다. 둘 다 인덱스를 반환하거나, 찾지 못하면 -1를 반환합니다.
public class Main {
public static void main(String[] args) {
int[] a = {2, 5, 8, 12, 16, 23}; // sorted, so binary search works
System.out.println(linear(a, 12)); // 3
System.out.println(binary(a, 12)); // 3
System.out.println(binary(a, 9)); // -1 (not found)
}
static int linear(int[] a, int target) {
for (int i = 0; i < a.length; i++)
if (a[i] == target) return i;
return -1;
}
static int binary(int[] a, int target) {
int lo = 0, hi = a.length - 1;
while (lo <= hi) {
int mid = (lo + hi) / 2;
if (a[mid] == target) return mid;
else if (a[mid] < target) lo = mid + 1;
else hi = mid - 1;
}
return -1;
}
}
이진 검색은 매 단계마다 범위를 반으로 나누므로, 정렬된 배열은 O(log n)에 검색됨
11.2
선택 및 삽입 정렬
English
Selection sort 选择排序 repeatedly finds the smallest remaining value and swaps it to the front. Insertion sort 插入排序 takes each value and slides it back into its place among the already-sorted values.
How the speeds compare:
Algorithm
Time
linear search
O(n)
binary search
O(log n), sorted arrays only
selection / insertion sort
O(n²)
merge sort (topic 10)
O(n log n)
Common mistakes
Binary search only works on a sorted array.
Linear search is O(n); binary search is O(log n) but needs the sort first.
Selection and insertion sort are O(n²) — clear to learn, slow on big data.
한국어
선택 정렬(selection sort)은 남은 값 중 가장 작은 값을 반복해서 찾아 맨 앞으로 스왑합니다. 삽입 정렬(insertion sort)은 각 값을 가져와 이미 정렬된 값들 사이에서 제자리로 밀어 넣습니다.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] a = {5, 2, 9, 1, 7};
for (int i = 0; i < a.length - 1; i++) {
int min = i;
for (int j = i + 1; j < a.length; j++)
if (a[j] < a[min]) min = j;
int t = a[min]; a[min] = a[i]; a[i] = t; // swap into place
}
System.out.println(Arrays.toString(a)); // [1, 2, 5, 7, 9]
}
}
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] a = {5, 2, 9, 1, 7};
for (int i = 1; i < a.length; i++) {
int key = a[i], j = i - 1;
while (j >= 0 && a[j] > key) { // shift bigger values right
a[j + 1] = a[j];
j--;
}
a[j + 1] = key; // drop key into the gap
}
System.out.println(Arrays.toString(a)); // [1, 2, 5, 7, 9]
}
}
A Scanner reads text one line at a time. For a real file you write new Scanner(new File("scores.txt")); here we wrap a String so the example runs anywhere. Use .split(" ") to split 拆分 a line into parts and Integer.parseInt(...) to parse 解析 a number from text.
한국어
Scanner는 텍스트를 줄 단위로 읽습니다. 실제 파일에서는 new Scanner(new File("scores.txt"))을 작성하지만, 여기서는 예제가 어디에서나 실행되도록 String를 감쌌습니다. 줄을 부분으로 나누려면 .split(" ")를 사용하고, 텍스트에서 숫자를 parsing하려면 Integer.parseInt(...)를 사용합니다.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// Real file: Scanner in = new Scanner(new File("scores.txt"));
String data = "Alice 80\nBob 95\nCara 72";
Scanner in = new Scanner(data);
int total = 0, count = 0;
while (in.hasNextLine()) {
String line = in.nextLine();
String[] parts = line.split(" "); // break the line on the space
total += Integer.parseInt(parts[1]);
count++;
}
System.out.println("average = " + (total / count)); // average = 82
}
}
Scanner는 hasNextLine이 true인 동안 줄을 읽음
12.2
AP FRQ 질문 유형
English
The AP CS A exam has four free-response 自由作答 questions, each a fixed shape:
Q1 — Methods & control: write methods to a given spec; loops, if, String/Math.
Q2 — Class design: write a full class (fields, constructor, methods) from a description.
Q3 — Array / ArrayList: process a 1-D array or ArrayList (search, count, build a new list).
Q4 — 2-D array: traverse a grid by row and column.
The skill is always the same: read the spec, write the method exactly as described, return the right type.
Common mistakes
nextInt() leaves the newline behind, so a following nextLine() reads an empty line — read it away first.
Check hasNext() before reading, to avoid running off the end of the file.
In the FRQ, read the method header carefully: match the return type and parameters exactly.
한국어
AP CS A 시험은 4개의 서술형 문제가 있으며, 각 문제는 고정된 형태를 가집니다:
Q1 — 메소드 및 제어: 주어진 규격에 따라 메소드를 작성; 루프, if, String/Math.
Q2 — 클래스 설계: 설명에서 전체 클래스(필드, 생성자, 메소드)를 작성합니다.
Q3 — 배열 / ArrayList: 1-D 배열이나 ArrayList을 처리(검색, 카운팅, 새 목록 생성).
Q4 — 2-D 배열: 행과 열을 통해 격자를 순회합니다.
이 기술은 항상 동일합니다: 규격을 읽고, 설명대로 정확히 메소드를 작성하고, 올바른 타입을 반환합니다.
public class Main {
public static void main(String[] args) {
// Q1 style: implement a method to a spec, then it is tested.
System.out.println(countEven(new int[]{4, 7, 10, 3, 6})); // 3
}
/** Returns how many values in arr are even. */
public static int countEven(int[] arr) {
int count = 0;
for (int x : arr)
if (x % 2 == 0) count++;
return count;
}
}
Common mistakes
nextInt()는 줄바꿈 문자를 그대로 두므로, 이어서 읽히는 nextLine()는 빈 줄이 됩니다. 먼저 이를 읽어야 합니다.