Mọi ngôn ngữ lập trình đều có nghi lễ khởi đầu: Hello World. Không phải vì chương trình này làm được gì đặc biệt — mà vì nó kiểm chứng rằng toàn bộ chuỗi công cụ (JDK + IDE) hoạt động đúng, và bạn hiểu cấu trúc tối thiểu để Java chạy được.
Bài này không chỉ dạy bạn viết Hello World — mà giải thích từng keyword, từng dòng và cơ chế đằng sau, để bạn không bị lạc khi gặp lỗi đầu tiên.
1. Analogy — "Thư gửi đi"
Hình dung bạn gửi một lá thư:
- Phong bì — có địa chỉ người gửi, người nhận, tem. Bưu điện cần thông tin này để biết xử lý ra sao.
- Nội dung thư — bên trong phong bì, đây là thứ người nhận thực sự đọc.
Mọi chương trình Java có cấu trúc tương tự:
- Class skeleton (
public class HelloWorld { ... }) — "phong bì" chứa thông tin để JVM nhận diện và xử lý. - Nội dung (code bên trong
main) — thứ thực sự được thực thi.
Thiếu phong bì → bưu điện không biết làm gì. Thiếu class skeleton → JVM không biết chạy gì.
💡 💡 Cách nhớ
Class = phong bì (bắt buộc, cấu trúc cố định). main method = trang đầu của thư (JVM đọc trang này trước tiên). Code bên trong main = nội dung thư (thứ thực sự xảy ra).
2. Chương trình Hello World
// HelloWorld.java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
Chạy chương trình:
# Compile source sang bytecode
javac HelloWorld.java
# Chay bytecode tren JVM
java HelloWorld
# Output:
# Hello, World!
Chỉ 5 dòng. Nhưng mỗi từ có lý do tồn tại.
3. Phân tích từng dòng
3.1 public class HelloWorld
public class HelloWorld {
Ba thành phần:
| Từ khoá | Ý nghĩa |
|---|---|
public | Access modifier — ai cũng có thể dùng class này (JVM, code khác) |
class | Khai báo đây là một class — đơn vị tổ chức code cơ bản nhất của Java |
HelloWorld | Tên class — phải khớp chính xác với tên file (bao gồm hoa/thường) |
Quy tắc tên file: Nếu class là public class HelloWorld, file phải tên HelloWorld.java. Không phải helloworld.java, không phải Hello_World.java. Sai tên file → javac từ chối compile.
3.2 public static void main(String[] args)
public static void main(String[] args) {
Đây là entry point — điểm JVM bắt đầu thực thi. Signature này cố định hoàn toàn:
| Phần | Giải thích |
|---|---|
public | JVM phải gọi được method này từ bên ngoài class |
static | JVM gọi trực tiếp mà không cần tạo object từ class trước |
void | Method không trả về giá trị gì (JVM không cần giá trị trả về) |
main | Tên mà JVM tìm kiếm khi khởi động — tên này cố định, không đổi được |
String[] args | Mảng chuỗi nhận từ command line (xem phần 5) |
💡 💡 Cách nhớ
Nghĩ main như cổng vào chính của toà nhà — JVM luôn đi qua đúng cổng này, không qua cổng khác. Thay đổi signature (bỏ static, đổi tên thành Main) → JVM không tìm thấy → chương trình không chạy được.
3.3 System.out.println("Hello, World!")
System.out.println("Hello, World!");
Đây là lời gọi method theo chuỗi:
System— class trong thư viện chuẩnjava.lang, đại diện cho hệ thốngout— field static củaSystem, là một objectPrintStreamđại diện cho console outputprintln— method củaPrintStream, in chuỗi ra console và xuống dòng
Nói ngắn: "Lấy object out từ class System, gọi method println trên nó với chuỗi "Hello, World!"".
Sự khác biệt giữa print và println:
System.out.print("A"); // In "A", KHONG xuong dong
System.out.print("B"); // In "B" ngay sau A
// Output: AB
System.out.println("A"); // In "A" ROI xuong dong
System.out.println("B"); // In "B" dong moi
// Output:
// A
// B
4. Sơ đồ từ source đến thực thi
flowchart LR src["HelloWorld.java<br/>(source code)"] javac["javac<br/>(compiler)"] cls["HelloWorld.class<br/>(bytecode)"] jvm["java<br/>(JVM launcher)"] out["Hello World!<br/>(console output)"] src --> javac --> cls --> jvm --> out
HelloWorld.java— source code bạn viết, con người đọc đượcjavac HelloWorld.java— compiler đọc source, tạo raHelloWorld.classHelloWorld.class— bytecode, JVM đọc được, không phụ thuộc OSjava HelloWorld— JVM launcher tải.class, tìm methodmain, bắt đầu chạy- Output — kết quả in ra console
5. Command-line arguments — args
String[] args không phải syntax vô nghĩa. Đó là mảng chuỗi nhận từ dòng lệnh khi bạn chạy chương trình.
// Chao.java
public class Chao {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("Xin chao, ban!");
} else {
// args[0] la tham so dau tien
System.out.println("Xin chao, " + args[0] + "!");
}
}
}
Chạy với tham số:
java Chao
# Output: Xin chao, ban!
java Chao An
# Output: Xin chao, An!
java Chao "Nguyen Van An"
# Output: Xin chao, Nguyen Van An!
Khi bạn chạy java Chao An Binh, args sẽ là ["An", "Binh"]:
args[0]="An"args[1]="Binh"args.length=2
6. Package — tổ chức class theo namespace
Khi dự án lớn, bạn có hàng chục class. Package là cách nhóm class liên quan lại — giống thư mục trong filesystem.
// com/example/HelloWorld.java
package com.example;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello from package!");
}
}
Convention đặt tên package: reverse domain name — tên miền đọc ngược:
- Công ty
example.com→ package prefixcom.example - Công ty
olhub.vn→ package prefixvn.olhub - Nhóm học tập → có thể dùng
com.yourname.projectname
Nếu không khai báo package:
Class thuộc default (unnamed) package — chạy được, nhưng không thể import từ package khác. Dùng được cho file học tập nhỏ, không nên dùng cho dự án thực tế.
# Compile class co package
javac com/example/HelloWorld.java
# Chay (phai chi ro fully qualified name)
java com.example.HelloWorld
Trong IntelliJ IDEA, package được tự động tạo khi bạn chọn thư mục khi tạo class mới — IDE lo phần này cho bạn.
7. Lỗi thường gặp khi bắt đầu
❌ Lỗi 1: Tên class không khớp tên file
HelloWorld.java:1: error: class HiWorld is public, should be declared in a file named HiWorld.java
public class HiWorld {
✅ Sửa: đổi tên file thành HiWorld.java hoặc đổi tên class thành HelloWorld.
❌ Lỗi 2: Signature main sai
Error: Main method not found in class HelloWorld, please define the main method as:
public static void main(String[] args)
Nguyên nhân thường gặp:
- Viết
void main()(thiếuString[] args) - Viết
public void main(thiếustatic) - Viết
Mainthay vìmain(Java case-sensitive)
✅ Sửa: copy chính xác public static void main(String[] args).
❌ Lỗi 3: Chạy trong thư mục sai
Error: Could not find or load main class HelloWorld
Caused by: java.lang.ClassNotFoundException: HelloWorld
✅ Sửa: phải chạy java HelloWorld từ thư mục chứa HelloWorld.class, không phải thư mục khác.
❌ Lỗi 4: Quên compile trước khi chạy
Error: Could not find or load main class HelloWorld
✅ Sửa: chạy javac HelloWorld.java trước, sau đó mới java HelloWorld.
8. Java 11+ — single-file execution
Từ Java 11, bạn có thể chạy file .java trực tiếp mà không cần compile thủ công:
# Truoc Java 11 -- 2 buoc
javac HelloWorld.java
java HelloWorld
# Tu Java 11 -- 1 buoc
java HelloWorld.java
JVM tự compile trong bộ nhớ và chạy ngay. Cơ chế bên dưới: JVM gọi javac internally, tạo bytecode tạm thời trong memory (không tạo file .class trên disk), rồi chạy bytecode đó.
Giới hạn của single-file execution:
- Chỉ dùng được với 1 file duy nhất — không thể import class từ file khác cùng project
- Không thể dùng khi file cần nhiều class phụ trợ
- Phù hợp cho script nhỏ, học tập, quick demo
9. Access modifiers — primer nhanh
Bài này dùng public nhiều lần. Đây là preview — chi tiết sẽ có ở module OOP:
| Modifier | Ai thấy được? | Thường dùng cho |
|---|---|---|
public | Tất cả — mọi class, mọi package | Class chính, method API |
protected | Cùng package + subclass | Method kế thừa |
| (không ghi gì) | Chỉ cùng package | Utility class nội bộ |
private | Chỉ trong class đó | Field, method nội bộ |
Quy tắc đơn giản cho giai đoạn này: class public, main public static — đây là pattern bắt buộc để JVM chạy được.
10. 📚 Deep Dive Oracle
ℹ️ 📚 Deep Dive Oracle (optional)
Spec chính thức:
- JLS §12.1 — Java Virtual Machine Startup — mô tả chính xác JVM tìm và gọi method
mainnhư thế nào, bao gồm điều kiện về signature - JLS §8.1 — Class Declarations — cú pháp khai báo class, access modifiers, và quy tắc về tên
- JEP 330 — Launch Single-File Source-Code Programs — spec cho tính năng
java HelloWorld.javatừ Java 11
Ghi chú đọc spec: JLS §12.1 giải thích tại sao signature main phải chính xác là public static void main(String[]) — JVM lookup method theo descriptor, sai một chút sẽ không match. Đây cũng là lý do Java 21 thử nghiệm "unnamed main method" (JEP 445) để đơn giản hóa việc học.
11. Tóm tắt
- Mọi chương trình Java cần ít nhất 1 class và 1
mainmethod với signature cố định. public class Foo— tên class phải khớp tên fileFoo.java.public static void main(String[] args)— JVM tìm chính xác signature này; sai là không chạy.System.out.println— in ra console và xuống dòng;System.out.printkhông xuống dòng.args— mảng chuỗi nhận từ command line, truy cập quaargs[0],args[1]...- Package — namespace tổ chức class; convention
reverse domain name(com.company.project). - Từ Java 11:
java HelloWorld.javachạy trực tiếp không cần compile thủ công.
12. Tự kiểm tra
- Vì sao
mainphải làstatic? Nếu bỏstaticđiều gì xảy ra và tại sao JVM không tự tạo object của class? - Chạy
java HelloWorldbáoClassNotFoundException. Nguyên nhân có thể là gì? Liệt kê ít nhất 3 nguyên nhân. System.out.println(10 + 20 + "hello")in gì? CònSystem.out.println("hello" + 10 + 20)in gì? Giải thích sự khác nhau.- Bạn có file
Foo.javachứapublic class Bar. Khijavac Foo.javaxảy ra điều gì? - Vì sao Java 11 có thể chạy
java HelloWorld.javamà không cầnjavac? Cơ chế đằng sau là gì?
Bài tiếp theo: Tư duy lập trình — input, xử lý, output