Java — Từ Zero đến Senior/Nhập môn & Tư duy lập trình/Hello World — cấu trúc một class Java
4/7
~15 phútNhập môn & Tư duy lập trình

Hello World — cấu trúc một class Java

Viết và hiểu chương trình Java đầu tiên từng dòng: class, main method, System.out.println, package, command-line args và lỗi thường gặp khi chạy.

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
publicAccess modifier — ai cũng có thể dùng class này (JVM, code khác)
classKhai báo đây là một class — đơn vị tổ chức code cơ bản nhất của Java
HelloWorldTê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ầnGiải thích
publicJVM phải gọi được method này từ bên ngoài class
staticJVM gọi trực tiếp mà không cần tạo object từ class trước
voidMethod không trả về giá trị gì (JVM không cần giá trị trả về)
mainTên mà JVM tìm kiếm khi khởi động — tên này cố định, không đổi được
String[] argsMả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:

  • Systemclass trong thư viện chuẩn java.lang, đại diện cho hệ thống
  • outfield static của System, là một object PrintStream đại diện cho console output
  • printlnmethod của PrintStream, 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 printprintln:

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
  1. HelloWorld.java — source code bạn viết, con người đọc được
  2. javac HelloWorld.java — compiler đọc source, tạo ra HelloWorld.class
  3. HelloWorld.class — bytecode, JVM đọc được, không phụ thuộc OS
  4. java HelloWorld — JVM launcher tải .class, tìm method main, bắt đầu chạy
  5. 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 prefix com.example
  • Công ty olhub.vn → package prefix vn.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ếu String[] args)
  • Viết public void main (thiếu static)
  • Viết Main thay 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:

ModifierAi thấy được?Thường dùng cho
publicTất cả — mọi class, mọi packageClass chính, method API
protectedCùng package + subclassMethod kế thừa
(không ghi gì)Chỉ cùng packageUtility class nội bộ
privateChỉ 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:

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 main method với signature cố định.
  • public class Foo — tên class phải khớp tên file Foo.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.print không xuống dòng.
  • args — mảng chuỗi nhận từ command line, truy cập qua args[0], args[1]...
  • Package — namespace tổ chức class; convention reverse domain name (com.company.project).
  • Từ Java 11: java HelloWorld.java chạy trực tiếp không cần compile thủ công.

12. Tự kiểm tra

  1. Vì sao main phả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?
  2. Chạy java HelloWorld báo ClassNotFoundException. Nguyên nhân có thể là gì? Liệt kê ít nhất 3 nguyên nhân.
  3. System.out.println(10 + 20 + "hello") in gì? Còn System.out.println("hello" + 10 + 20) in gì? Giải thích sự khác nhau.
  4. Bạn có file Foo.java chứa public class Bar. Khi javac Foo.java xảy ra điều gì?
  5. Vì sao Java 11 có thể chạy java HelloWorld.java mà không cần javac? Cơ chế đằng sau là gì?

Bài tiếp theo: Tư duy lập trình — input, xử lý, output