This page needs a recent browser (with SharedArrayBuffer support). Please update Chrome, Edge, Firefox or Safari to the latest version. · Trang này cần trình duyệt gần đây (hỗ trợ SharedArrayBuffer). Vui lòng cập nhật Chrome, Edge, Firefox hoặc Safari lên phiên bản mới nhất.
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 ;.
Tiếng Việt
Mỗi chương trình Java đều nằm bên trong một class. Nó bắt đầu tại một method tên là main. System.out.println(...) in ra một dòng; System.out.print(...) in ra mà không xuống dòng mới.
public class Main {
public static void main(String[] args) {
System.out.println("Hello, world!");
System.out.println("I am learning Java.");
}
}
Java được biên dịch: trình biên dịch kiểm tra toàn bộ chương trình, sau đó nó chạy.
Mỗi câu lệnh kết thúc bằng dấu chấm phẩy ;.
Java programs live in a class and start at main
1.2
Variables & primitive types
English
A variable 变量 must declare 声明 its type. Common primitive types 基本类型: int (whole number), double (decimal), boolean (true/false), char (one letter).
Tiếng Việt
Một biến cần khai báo kiểu của nó. Các kiểu nguyên thủy phổ biến: int (số nguyên), double (thập phân), boolean (true/false), char (một ký tự).
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
Bình luận & phong cách
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).
println adds a new line; print does not.
Tiếng Việt
Một comment là // (một dòng) hoặc /* ... */ (một khối). Thụt lề code bên trong ngoặc nhọn { }. Tên class viết hoa; biến và method dùng camelCase (viết thường chữ đầu).
public class Main {
public static void main(String[] args) {
// greet the user
String firstName = "Mei";
System.out.println("Hi, " + firstName);
}
}
Lỗi thường gặp
Mỗi câu lệnh kết thúc bằng dấu chấm phẩy ;.
main phải chính xác là public static void main(String[] args).
Java arithmetic 算术 uses + - * / and % (remainder). With two ints, / is integer division 整数除法 — it drops the decimal. +=, -=, and ++ are shortcuts.
Tiếng Việt
Toán học Java sử dụng + - * / và % (phần dư). Với hai int, / là phép chia số nguyên — nó bỏ phần thập phân. +=, -=, và ++ là các cách tắt.
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.
Tiếng Việt
Một số giá trị là các đối tượng có methods. String có .length(), .substring(), .toUpperCase(). Math có Math.max, Math.sqrt, Math.pow. Wrapper classes (Integer, Double) đóng gói một primitive — ví dụ: 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() trả về một double ngẫu nhiên từ 0.0 trở lên (nhưng không bao gồm) 1.0. Nhân tỷ lệ và cast để lấy số nguyên — đây là idiom của AP:
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) và Integer.MIN_VALUE là giới hạn của int; vượt qua chúng sẽ bị cuộn vòng lại (overflow).
Một biến đối tượng không trỏ vào bất kỳ đối tượng nào chứa null; gọi một method trên nó sẽ ném 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.
Tiếng Việt
Cast thay đổi kiểu của một giá trị. (int) loại bỏ phần thập phân; (double) tránh phép chia số nguyên khi bạn cần kết quả chính xác.
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
}
}
Lỗi thường gặp
Phép chia số nguyên: 5 / 2 là 2, không phải 2.5. Cast trước: (double) 5 / 2.
So sánh Strings (và các đối tượng khác) với .equals(), không phải ==.
== trên hai đối tượng kiểm tra xem chúng có phải là CÙNG một đối tượng hay không, không phải xem chúng có giống nhau về mặt biểu diễn hay không.
if runs a block when a condition 条件 is true; else if and else add more cases. The condition goes in ( ), the block in { }.
Tiếng Việt
if chạy một block khi một điều kiện đúng; else if và else thêm nhiều trường hợp hơn. Điều kiện nằm trong ( ), block nằm trong { }.
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 chọn nhánh true; else chọn nhánh false
3.2
Logical operators & comparisons
English
Compare with ==, !=, <, >, <=, >= — a comparison 比较 gives a boolean. Combine with && (and), || (or), ! (not) — the logical operators 逻辑运算符. For Strings, use .equals(...), not==.
Tiếng Việt
So sánh với ==, !=, <, >, <=, >= — một phép so sánh cho ra một boolean. Kết hợp với && (and), || (or), ! (not) — các toán tử logic. Đối với Strings, hãy dùng .equals(...), không phải==.
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.
Tiếng Việt
switch chọn giữa nhiều giá trị cố định. Mỗi case kết thúc bằng break; default là giá trị dự phòng.
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");
}
}
}
Lỗi thường gặp
Một điều kiện phải là một boolean; if (x = 5) sẽ không biên dịch được (hãy dùng ==).
Mỗi switch case cần một break;, nếu không điều khiển sẽ rơi vào case tiếp theo.
A while loop repeats while a condition is true. Change something inside, or it loops forever.
Tiếng Việt
Một while loop lặp lại trong khi một điều kiện đúng. Thay đổi thứ gì đó bên trong, hoặc nó sẽ lặp vô tận.
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
Vòng lặp for
English
A for loop packs the start, the condition, and the step into one line. Best when you know the count.
Tiếng Việt
Một for loop gom phần khởi tạo, điều kiện và bước tăng/giảm vào một dòng. Tốt nhất khi bạn biết số lần lặp.
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
Tích lũy
English
The accumulator 累加器 pattern: start a variable before the loop, then update it each turn.
Tiếng Việt
Mẫu tích lũy: khởi tạo một biến trước loop, sau đó cập nhật nó mỗi lần lặp.
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
Vòng lặp lồng nhau
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.
Tiếng Việt
Một loop bên trong một loop là loop lồng nhau. Loop trong chạy trọn vẹn ở mỗi lần lặp của loop ngoài.
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();
}
}
}
Lỗi thường gặp
for (int i = 0; i < n; i++) chạy n lần (từ 0 đến n - 1); việc sử dụng <= sẽ chạy thêm một lần nữa.
Đừng đặt dấu chấm phẩy ngay sau for (...) hoặc while (...) — nó sẽ tạo ra một loop rỗng.
Khai báo biến đếm trong header for để phạm vi của nó kết thúc cùng với loop.
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:
Tiếng Việt
Một String là văn bản. Các methods hữu ích: .length(), .charAt(i), .substring(a, b), .indexOf(x), .toUpperCase(), .equals(...). Strings là bất biến — mỗi method trả về một mới 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
}
}
Các methods bạn sẽ dùng hàng ngày:
Method
Ý nghĩa
Ví dụ → kết quả
.length()
bao nhiêu ký tự
"Hi".length() → 2
.charAt(i)
một ký tự
"Hi".charAt(0) → H
.substring(a, b)
phần, dừng trước b
"Python".substring(0, 3) → Pyt
.substring(a)
từ a đến cuối
"Python".substring(3) → hon
.indexOf(x)
vị trí đầu tiên, -1 nếu không có
"banana".indexOf("na") → 2
.equals(s)
cùng văn bản?
"hi".equals("hi") → true
.compareTo(s)
thứ tự: âm / 0 / dương
"apple".compareTo("banana") → âm
compareTo sắp xếp Strings theo thứ tự từ điển — đề thi AP sử dụng nó cho các câu hỏi sắp xếp:
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)
}
}
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.
Tiếng Việt
Nối các chuỗi bằng + (nối chuỗi). Duyệt qua từng ký tự bằng một loop và .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
}
}
Khi bạn xây dựng một String dài trong loop, StringBuilder nhanh hơn nhiều: append các mảnh, sau đó gọi .toString() một lần.
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
}
}
Lỗi thường gặp
Strings là bất biến: s.toUpperCase() trả về một String mới, nên lưu kết quả.
Đọc một ký tự bằng s.charAt(i); độ dài là s.length() (một method, có ()).
Xây dựng String bằng += trong một loop lớn rất chậm; hãy dùng một StringBuilder.
An array 数组 holds a fixed number of values of one type. Index from 0, and get the size with .length.
Tiếng Việt
Một mảng giữ một số lượng giá trị cố định của một kiểu. Index từ 0, và lấy kích thước bằng .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
}
}
Giá trị nguyên thủy giữ giá trị; biến mảng giữ tham chiếu đến đối tượng mảng
6.2
Thuật toán mảng
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.
Tiếng Việt
Duyệt mảng bằng vòng lặp để tìm giá trị lớn nhất, tổng, số lượng hoặc thực hiện tìm kiếm. Vòng lặp for-each (for (int x : a)) đọc từng giá trị theo thứ tự.
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
Mảng 2 chiều
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.
Tiếng Việt
Mảng 2-D là một lưới gồm các hàng và cột: 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
}
}
Lỗi thường gặp
Kích thước của mảng là a.length (không có ngoặc, không có ()), và nó được cố định ngay khi được tạo ra.
Các chỉ số hợp lệ nằm từ 0 đến a.length - 1; a[a.length] sẽ gây ra ArrayIndexOutOfBoundsException.
Một int[5] mới được điền bằng số không, không để trống.
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).
Tiếng Việt
Một ArrayList là danh sách có thể thay đổi kích thước — nó mở rộng và thu nhỏ khi bạn thêm hoặc xóa mục. Nó lưu trữ các đối tượng, vì vậy hãy dùng kiểu bao bọc như Integer (không phải int). Phần <Integer> là một kiểu tổng quát. Các phương thức chính: .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 trên danh sách có thể thay đổi kích thước
7.2
Thuật toán ArrayList & lỗi 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.
Tiếng Việt
.remove(i) dịch chuyển mọi phần tử sau về phía trái một vị trí. Nếu bạn xóa trong khi đếm ilên, bạn sẽ bỏ sót phần tử tiếp theo. Cách sửa: lặp ngược, hoặc không tăng i sau khi xóa.
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]
}
}
Lỗi thường gặp
ArrayList sử dụng .size(), .get(i) và .add(...) — không phải [] mà bạn dùng trên mảng.
Xóa phần tử trong khi duyệt theo chỉ số từ đầu đến cuối sẽ bỏ sót phần tử tiếp theo (lỗi remove). Hãy duyệt ngược lại, hoặc sử dụng iterator.
Lưu trữ các đối tượng, không phải giá trị nguyên thủy: hãy dùng ArrayList<Integer>, và Java tự động đóng hộp int thành đối tượng.
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:
Tiếng Việt
Một lớp là bản thiết kế cho các đối tượng. Các trường của nó lưu dữ liệu, constructor thiết lập một đối tượng mới, và các phương thức là các hành động. this.name có nghĩa là "name của đối tượng này". Tạo một đối tượng với 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++;
}
}
Một thành viên static thuộc về lớp đó, không thuộc về bất kỳ đối tượng cụ thể nào. Gọi phương thức tĩnh theo tên lớp — ví dụ Math.max — và một trường tĩnh được chia sẻ bởi mọi đối tượng:
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;
}
}
Fields lưu trạng thái; constructor xây dựng; methods thực thi hành động
8.2
Đóng gói (Encapsulation)
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).
Tiếng Việt
Encapsulation (bao đóng) có nghĩa là ẩn dữ liệu phía sau các phương thức. Đánh dấu các trường private để mã bên ngoài không thể truy cập trực tiếp; cung cấp một method truy vấn (getter) để đọc, và một method để thay đổi chúng an toàn. Phương thức này có thể bảo vệ dữ liệu — ở đây khoản tiền gửi phải là số dương.
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;
}
}
Lỗi thường gặp
Constructor có tên lớp và không có kiểu trả về (thậm chí cả void).
Sử dụng this.field để phân biệt trường với tham số cùng tên.
Khai báo các trường là private và truy cập chúng thông qua các phương thức getter/setter (bao encapsulation).
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(...).
Tiếng Việt
Kế thừa cho phép một lớp con tái sử dụng một lớp cha. Viết class Cat extends Animal và Cat nhận được Animal's fields and methods for free. Call the parent constructor with 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 và Dog kế thừa Animal: chúng thừa hưởng các thành viên của nó và thêm vào những cái riêng
9.2
Đa hình & 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.
Tiếng Việt
Một lớp con có thể ghi đè một phương thức để thay thế phiên bản của cha. Đa hình có nghĩa là một biến Shape có thể chứa bất kỳ kiểu con nào, và Java chọn đúng toString tại thời gian chạy. System.out.println(obj) tự động gọi 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
}
Lỗi thường gặp
Một phương thức ghi đè phải khớp chính xác chữ ký; hãy thêm @Override để trình biên dịch bắt được sai sót.
super(...) phải là dòng đầu tiên của constructor subclass.
Một đối tượng subclass IS-A đối tượng superclass, nhưng không phải ngược lại.
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.
Tiếng Việt
Đệ quy (recursion) là một phương thức gọi chính nó. Mọi đệ quy đều cần một base case (khi nào thì dừng) và một cuộc gọi đệ quy tiến gần đến nó. Không có base case, nó sẽ không bao giờ dừng và bị crash với lỗi stack overflow.
Call stack cho factorial(3): mỗi cuộc gọi chờ đợi, rồi trả về theo thứ tự ngược lại
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)!
}
}
Theo dõi nó: factorial(5) chờ đợi factorial(4), cái gì đó chờ đợi factorial(3)… xuống đến factorial(1) trả về 1. Sau đó các câu trả lời nhân ngược lên: 1 → 2 → 6 → 24 → 120.
Đệ quy cũng hoạt động trên Strings — gọt bỏ một ký tự mỗi lần gọi:
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 là thuật toán sắp xếp đệ quy trong đề thi AP: chia mảng thành hai nửa, sắp xếp mỗi nửa đệ quy, sau đó gộp hai nửa đã sắp xếp lại. Nó chạy trong O(n log n) — nhanh hơn nhiều so với các thuật toán O(n²) trên mảng lớn.
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];
}
}
Lỗi thường gặp
Quy hồi cần một trường hợp cơ sở, nếu không sẽ gây ra StackOverflowError.
Mỗi cuộc gọi đệ quy phải di chuyển GẦN HƠN đến base case.
Trace một ví dụ nhỏ bằng tay để kiểm tra xem đệ quy có trả về giá trị đúng không.
Trong merge sort, bước merge làm công việc thực sự; đệ quy chỉ chia mảng.
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.
Tiếng Việt
Tìm kiếm tuyến tính kiểm tra từng phần tử — hoạt động trên mọi mảng. Tìm kiếm nhị phân nhanh hơn nhiều nhưng cần một mảng đã sắp xếp: nó xem xét phần tử ở giữa, sau đó loại bỏ một nửa mỗi bước. Cả hai đều trả về chỉ số, hoặc -1 nếu không tìm thấy.
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;
}
}
Binary search chia đôi phạm vi mỗi bước, nên mảng đã sắp xếp được tìm kiếm trong O(log n)
11.2
Sắp xếp chọn & sắp xếp chèn
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.
Tiếng Việt
Sắp xếp chọn (selection sort) liên tục tìm giá trị nhỏ nhất còn lại và hoán đổi nó lên đầu. Sắp xếp chèn (insertion sort) lấy từng giá trị và trượt nó trở lại vị trí phù hợp trong số các giá trị đã được sắp xếp.
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]
}
}
So sánh tốc độ:
Thuật toán
Thời gian
linear search
O(n)
binary search
O(log n), chỉ mảng đã sắp xếp
selection / insertion sort
O(n²)
merge sort (đề mục 10)
O(n log n)
Lỗi thường gặp
Binary search chỉ hoạt động trên một mảng đã sắp xếp.
Linear search là O(n); binary search là O(log n) nhưng cần sắp xếp trước.
Selection và insertion sort là O(n²) — dễ học, nhưng chậm trên dữ liệu lớn.
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.
Tiếng Việt
Một Scanner đọc văn bản từng dòng một. Đối với một tập tin thực tế, bạn viết new Scanner(new File("scores.txt")); ở đây chúng tôi bao quanh một String để ví dụ chạy ở bất cứ đâu. Sử dụng .split(" ") để tách một dòng thành các phần và Integer.parseInt(...) để phân tích một số từ văn bản.
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 đọc dòng trong khi hasNextLine là true
12.2
Các loại câu hỏi FRQ của AP
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.
Tiếng Việt
Đề thi AP CS A có bốn câu hỏi tự luận, mỗi câu có dạng cố định:
Q1 — Phương thức & điều khiển: viết các phương thức theo yêu cầu đã cho; vòng lặp, if, String/Math.
Q2 — Thiết kế lớp: viết một lớp đầy đủ (trường, khởi tạo, phương thức) từ mô tả.
Q3 — Mảng / ArrayList: xử lý mảng 1-D hoặc ArrayList (tìm kiếm, đếm, xây dựng danh sách mới).
Q4 — Mảng 2-D: duyệt qua lưới theo hàng và cột.
Kỹ năng luôn giống nhau: đọc yêu cầu, viết phương thức đúng như mô tả, trả về kiểu dữ liệu chính xác.
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;
}
}
Lỗi thường gặp
nextInt() giữ lại ký tự xuống dòng, nên nextLine() tiếp theo sẽ đọc một dòng trống — hãy đọc nó đi trước.
Kiểm tra hasNext() trước khi đọc, để tránh vượt quá cuối tập tin.
Trong FRQ, đọc kỹ phần khai báo phương thức: khớp chính xác kiểu trả về và tham số.
Pick one and the site follows you — notes, papers, videos and practice all open on it. · Chọn một môn và trang sẽ điều hướng theo — ghi chú, tài liệu, video và bài tập đều mở ở đó.
Type to search notes, lessons, code, vocabulary and past-paper questions across every subject. · Nhập để tìm ghi chú, bài học, mã, từ vựng và câu hỏi đề thi cũ trên mọi môn học.