1. Thư mục src — nơi “sống” của mã nguồn bạn
Nếu dự án Java là một ngôi nhà, thì thư mục src — là phòng khách ấm cúng, nơi tụ họp các “cư dân” chính (các lớp của bạn). Tất cả tệp mã nguồn đều đặt ở đây, không phải ở gốc dự án, không phải trong thư mục cấu hình và càng không phải trên Desktop (dù có “thèm” đến mấy).
Vì sao cần tách mã nguồn khỏi những thứ khác?
- Trong thư mục
srcchỉ có các tệp bạn tự viết: .java. - Mọi thứ phát sinh trong quá trình build (ví dụ, các tệp .class, tệp tạm) sẽ nằm ở thư mục khác (out, build, target, v.v.).
- Điều này giúp dễ điều hướng, dự án gọn gàng hơn và IDE “vui vẻ” hơn.
Ví dụ cấu trúc một dự án đơn giản:
MyFirstProject/
├── .idea/ # tệp hệ thống của IntelliJ IDEA, đừng đụng vào
├── out/ # nơi sinh ra các tệp .class đã biên dịch
├── src/ # mã nguồn của bạn ở đây!
│ └── Main.java
├── MyFirstProject.iml
└── README.md
Quan trọng:
Mọi thứ bạn tự viết — lớp (class), gói (package), interface — phải nằm trong thư mục src. Đừng đặt vào đó hình ảnh, nhạc hay công thức bí mật — đã có các thư mục khác cho việc này.
2. Gói package
Trong Java, thông lệ là nhóm các lớp theo “gói” — giống như thư mục trong hệ thống tệp nhưng dành cho lớp. Package giúp:
- Tránh xung đột tên: nếu trong dự án có hai lớp
Main— ở các package khác nhau, chúng sẽ không cản trở nhau. - Tổ chức mã theo logic (ví dụ,
com.codegym.tasks,com.mycompany.utils). - Quản lý phạm vi truy cập tới lớp và phương thức.
Cú pháp khai báo package
Ở đầu mỗi tệp Java (trước mọi import và class) có dòng:
package com.codegym.lesson05;
Điều này có nghĩa: lớp trong tệp này thuộc package com.codegym.lesson05.
Quan trọng:
Thư mục trong hệ thống tệp phải trùng với tên package! Nếu bạn viết package com.codegym.lesson05;, thì đường dẫn tới tệp sẽ là:
src/com/codegym/lesson05/Main.java
Cách tạo package trong IntelliJ IDEA
- Trong bảng Project, nhấp chuột phải vào thư mục
src. - Chọn New → Package.
- Nhập tên, ví dụ: com.codegym.lesson05 (IDE sẽ tự tạo các thư mục lồng nhau).
- Bây giờ hãy tạo một lớp mới bên trong package này. Nhấp chuột phải vào thư mục com.codegym.lesson05 và chọn New → Java Class. Rồi nhập tên
Ví dụ:
src/
└── com/
└── codegym/
└── lesson05/
└── User.java
Vì sao không nên nhét tất cả vào src?
Nếu đổ tất cả lớp lẫn lộn, dự án sẽ nhanh chóng biến thành một “bãi tập kết”, nơi tìm được tệp cần còn khó hơn tìm sạc laptop trong ký túc xá sinh viên. Hãy dùng package — sẽ dễ mở rộng dự án, tích hợp thư viện bên thứ ba và chia sẻ mã giữa các nhóm hơn.
3. Tên lớp đầy đủ
Mỗi lớp trong Java bắt buộc phải nằm trong một package. Package chỉ là “thư mục” bên trong thư viện lớp. Ví dụ:
- Lớp System nằm trong package java.lang. Tên đầy đủ của nó — java.lang.System.
- Lớp Scanner nằm trong package java.util. Tên đầy đủ của nó — java.util.Scanner.
- Lớp ArrayList cũng ở java.util, nên tên đầy đủ — java.util.ArrayList.
Tức là tên lớp đầy đủ = tên package + dấu chấm + tên lớp.
Thử dùng điều này trong mã:
java.util.Scanner sc = new java.util.Scanner(System.in);
String name = sc.nextLine();
System.out.println("Xin chào, " + name);
Ở đây chúng ta viết rõ java.util.Scanner. Trình biên dịch hiểu chính xác lớp nào đang được nhắc tới, kể cả khi trong chương trình có các lớp khác cùng tên Scanner.
Điều này rất quan trọng: tên lớp có thể trùng, nhưng tên đầy đủ luôn là duy nhất.
Vì sao cần tên đầy đủ?
Hãy tưởng tượng, chúng ta có hai lớp Date khác nhau:
- java.util.Date (lớp cũ để làm việc với ngày),
- java.sql.Date (ngày dùng cho làm việc với cơ sở dữ liệu).
Nếu bạn chỉ viết:
Date d = new Date();
Trình biên dịch sẽ không hiểu bạn muốn dùng Date nào. Nhưng nếu viết tên đầy đủ:
java.util.Date d1 = new java.util.Date();
java.sql.Date d2 = new java.sql.Date(System.currentTimeMillis());
— sẽ không còn nhầm lẫn.
4. Toán tử import
Việc mỗi lần đều viết tên đầy đủ của lớp là bất tiện. Đó là lý do trong Java có toán tử import.
Nếu chúng ta viết:
import java.util.Scanner;
Điều này có nghĩa: “Trong chương trình này tôi sẽ dùng lớp Scanner từ package java.util”. Sau đó ta có thể chỉ viết:
Scanner sc = new Scanner(System.in);
và trình biên dịch sẽ hiểu đó chính là java.util.Scanner.
Import thông thường (một lớp)
Đây là cách phổ biến nhất. Ta chỉ định một lớp cụ thể:
import java.util.Scanner;
import java.util.ArrayList;
Bây giờ có thể viết tên ngắn: Scanner, ArrayList.
Import toàn bộ package *
Đôi khi chương trình dùng nhiều lớp từ cùng một package. Khi đó có thể viết:
import java.util.*;
Nghĩa là: “Cho phép sử dụng tất cả các lớp trong package java.util mà không cần tên đầy đủ”.
Bây giờ có thể viết:
Scanner sc = new Scanner(System.in);
ArrayList<String> list = new ArrayList<>();
Nhưng cần nhớ: import java.util.*; chỉ import các lớp trong package java.util, không bao gồm các subpackage. Ví dụ, lớp java.util.concurrent.ConcurrentHashMap sẽ không được import. Bạn phải import riêng.
Những điều import không làm được
- Không thể dùng
importbên trong phương thức — nó chỉ được viết ở đầu tệp. importkhông nạp lớp vào bộ nhớ. Nó chỉ nói cho trình biên dịch biết lấy lớp từ đâu.importkhông thể thay thế tên đầy đủ nếu có hai lớp trùng tên.
5. Classpath — cách Java tìm các lớp của bạn
Classpath — là “lộ trình” mà Java dùng để tìm các lớp của bạn khi chạy chương trình. Hãy coi nó như danh sách thư mục nơi Java sẽ tìm các tệp .class cần thiết (phiên bản đã biên dịch của các tệp .java của bạn).
Mặc định IDE sẽ tự thêm thư mục src (hoặc thư mục chứa các lớp đã biên dịch, ví dụ, out/production/ProjectName) vào classpath. Tức là, nếu bạn viết lớp trong package com.codegym.lesson05, Java sẽ tìm nó theo đường dẫn:
out/production/ProjectName/com/javarush/lesson05/Main.class
Classpath trong IntelliJ IDEA hoạt động thế nào?
- Khi bạn chạy chương trình qua IDE, IDE sẽ tự động thiết lập classpath cần thiết.
- Nếu bạn chạy chương trình từ dòng lệnh, bạn cần chỉ rõ classpath bằng cờ -cp hoặc -classpath.
- Tất cả các lớp trong dự án của bạn và thư viện liên kết phải nằm trong các thư mục được liệt kê trong classpath.
6. Tổ chức mã trong dự án
Một lớp — một tệp
Trong Java, thông lệ là mỗi lớp public nằm trong một tệp riêng và tệp đó có tên trùng với tên lớp. Ví dụ, nếu bạn có lớp Person, thì tệp phải có tên Person.java.
Ví dụ:
src/com/javarush/lesson05/Person.java
package com.codegym.lesson05;
public class Person {
String name;
}
Tên tệp và tên lớp phải trùng khớp
Nếu lớp có tên MySuperClass, thì tệp phải là MySuperClass.java. Đây không phải là sở thích cá nhân, mà là yêu cầu của trình biên dịch Java. Nếu nhầm lẫn — bạn sẽ gặp lỗi ở bước biên dịch.
Lưu tài nguyên (ảnh, tệp văn bản) ở đâu?
- Với tài nguyên, thường tạo một thư mục riêng, ví dụ, resources hoặc res.
- Trong IntelliJ IDEA, có thể thêm thư mục này bằng cách nhấp chuột phải vào thư mục: Mark Directory as → Resources Root.
- Mã Java có thể truy cập các tệp này qua
classpath.
Ví dụ cấu trúc:
MyFirstProject/
├── src/
│ └── com/javarush/lesson05/
│ └── Main.java
├── resources/
│ └── config.txt
8. Lỗi thường gặp khi làm việc với cấu trúc dự án
Không khớp giữa cấu trúc thư mục và package
Nếu ở đầu tệp có package com.codegym.lesson05;, còn tệp lại nằm ở src/Main.java, trình biên dịch sẽ báo lỗi "package does not exist" hoặc "class not found". Luôn đảm bảo thư mục khớp với tên package!
Không khớp tên tệp và tên lớp
Nếu lớp có tên Person, còn tệp — People.java, bạn sẽ nhận lỗi "class Person is public, should be declared in a file named Person.java".
Di chuyển tệp thủ công mà quên cập nhật package
Nếu bạn di chuyển tệp sang thư mục khác nhưng quên đổi dòng package, chương trình sẽ không biên dịch được. Hãy thực hiện việc này trong cửa sổ Project của IDE — IDE sẽ tự cập nhật package!
Tài nguyên không được thêm vào classpath
Nếu bạn lưu các tệp (ví dụ, văn bản) ngoài thư mục resources và không đánh dấu thư mục đó là Resources Root, chương trình sẽ không thể tìm chúng thông qua classpath.
GO TO FULL VERSION