Hầu hết các câu trả lời ở đây đã tuyên bố rằng không có thứ gọi là gói con trong Java, nhưng điều đó không hoàn toàn chính xác. Thuật ngữ này đã có trong Đặc tả ngôn ngữ Java từ thời Java 6 và có thể quay trở lại (dường như không có phiên bản JLS có thể truy cập tự do cho các phiên bản Java trước đó). Ngôn ngữ xung quanh các gói con không thay đổi nhiều trong JLS kể từ Java 6.
Các thành viên của gói là các gói con của nó và tất cả các loại lớp cấp cao nhất và loại giao diện cấp cao nhất được khai báo trong tất cả các đơn vị biên dịch của gói.
Ví dụ: trong API nền tảng Java SE:
- Các gói phần mềm
java
có các gói con awt
, applet
, io
, lang
, net
, và util
các đơn vị, nhưng không có biên dịch.
- Gói
java.awt
này có một gói con được đặt tên image
, cũng như một số đơn vị biên dịch có chứa các khai báo của các loại lớp và giao diện.
Khái niệm gói phụ có liên quan, vì nó thực thi các ràng buộc đặt tên giữa các gói và các lớp / giao diện:
Một gói có thể không chứa hai thành viên cùng tên hoặc kết quả lỗi thời gian biên dịch.
Dưới đây là một số ví dụ:
- Bởi vì gói
java.awt
có một gói con image
, nó không thể (và không) chứa một khai báo của một lớp hoặc loại giao diện được đặt tên image
.
- Nếu có một gói có tên
mouse
và một loại thành viên Button
trong gói đó (sau đó có thể được gọi là mouse.Button
), thì không thể có bất kỳ gói nào có tên đủ điều kiện mouse.Button
hoặc mouse.Button.Click
.
- Nếu
com.nighthacks.java.jag
là tên đủ điều kiện của một loại, thì không thể có bất kỳ gói nào có tên đủ điều kiện là com.nighthacks.java.jag
hoặc com.nighthacks.java.jag.scrabble
.
Tuy nhiên, hạn chế đặt tên này là ý nghĩa duy nhất đủ khả năng để đóng gói theo ngôn ngữ:
Cấu trúc đặt tên phân cấp cho các gói nhằm thuận tiện cho việc tổ chức các gói liên quan theo cách thông thường, nhưng bản thân nó không có ý nghĩa gì ngoài việc cấm gói có gói con có cùng tên đơn giản như loại cấp cao nhất được khai báo trong gói đó .
Ví dụ, không có mối quan hệ truy cập đặc biệt giữa một gói có tên oliver
và một gói khác có tên oliver.twist
, hoặc giữa các gói có tên evelyn.wood
và evelyn.waugh
. Nghĩa là, mã trong gói có tên oliver.twist
không có quyền truy cập tốt hơn vào các loại được khai báo trong gói oliver
so với mã trong bất kỳ gói nào khác.
Với bối cảnh này, chúng ta có thể tự trả lời câu hỏi. Vì rõ ràng không có mối quan hệ truy cập đặc biệt giữa một gói và gói phụ của nó, hoặc giữa hai gói phụ khác nhau của gói cha, nên không có cách nào trong ngôn ngữ để hiển thị một phương thức cho hai gói khác nhau theo cách được yêu cầu. Đây là một quyết định thiết kế tài liệu, cố ý.
Phương thức có thể được công khai và tất cả các gói (bao gồm odp.proj
và odp.proj.test
) sẽ có thể truy cập các phương thức đã cho hoặc phương thức có thể được đặt ở chế độ riêng tư (khả năng hiển thị mặc định) và tất cả các mã cần truy cập trực tiếp vào nó phải được đặt gói (phụ) giống như phương thức.
Điều đó nói rằng, một thực tiễn rất chuẩn trong Java là đặt mã kiểm tra vào cùng gói với mã nguồn, nhưng ở một vị trí khác trên hệ thống tệp. Ví dụ, trong công cụ xây dựng Maven , quy ước sẽ là đặt các tệp nguồn và kiểm tra này vào src/main/java/odp/proj
và
src/test/java/odp/proj
, tương ứng. Khi công cụ xây dựng biên dịch cái này, cả hai bộ tệp kết thúc trong odp.proj
gói, nhưng chỉ các src
tệp được bao gồm trong tạo phẩm sản xuất; các tệp kiểm tra chỉ được sử dụng tại thời điểm xây dựng để xác minh các tệp sản xuất. Với thiết lập này, mã kiểm tra có thể tự do truy cập bất kỳ gói riêng tư hoặc mã được bảo vệ nào của mã mà nó đang kiểm tra, vì chúng sẽ nằm trong cùng một gói.
Trong trường hợp bạn muốn chia sẻ mã trên các gói con hoặc gói anh chị em không phải là trường hợp thử nghiệm / sản xuất, một giải pháp tôi đã thấy một số thư viện sử dụng là đặt mã chia sẻ đó thành công khai, nhưng tài liệu đó là dành cho thư viện nội bộ chỉ sử dụng.