Được chình sửa ngày 26/11/2020.
Chào mừng các bạn đến với bài học Java số 19, bài học về Package. Bài học này nằm trong chuỗi bài học lập trình ngôn ngữ Java của Yellow Code Books.
Với hai bài học về Thuộc tính và Phương thức mà các bạn đã làm quen, mình đều có để ra đó và không nói gì cả kiến thức về khả_năng_truy_cập. Cái khả năng truy cập này lại rất phụ thuộc vào việc tổ chức cấu trúc project theo package. Vậy thì package là gì và nó giúp ích được gì cho project của bạn? Hôm nay mình sẽ nói rõ về package trước. Và rồi đến bài học sau các bạn sẽ thấy chúng liên quan mật thiết đến các khả_năng_truy_cập của các lớp như thế nào nhé. Mời các bạn cùng xem.
Package
Package – Dịch ra tiếng việt là Gói, hay Bó. Công dụng của nó thì y chang như nghĩa mà nó mang lại. Nó sẽ giúp chúng ta hai việc.
- Bó – Hay có thể nói công dụng này là gom các Java class mà bạn đã tạo ra làm thành các nhóm. Mỗi nhóm như vậy bao gồm các class có chung một công năng nào đó. Mục đích chính là giúp bạn tổ chức nên những kiến trúc rõ ràng hơn cho source code của ứng dụng.
- Gói – Có thể hiểu rằng đây là công dụng đóng gói. Nó giúp bạn xuất bản các thư viện đến cho người dùng theo dạng các gói (người dùng ở đây hiểu theo nghĩa là các lập trình viên khác ấy nhé). Như bạn có từng làm quen ở bài học số 7, khi đó bạn dùng đến lớp Scanner để đọc dữ liệu nhập vào từ console, nhưng nếu không có dòng import java.util.Scanner ở trên cùng của file class thì sẽ không thể nào dùng được Scanner. Lúc đó mình có nhắc một tí đến package, và java.util chính là package, package này đã giúp gói lớp Scanner vào để mang đến cho bạn dùng đó.
Nếu như với project đơn giảnh như OOPLearning mà chúng ta đã thực hành từ các bài trước, thì bạn hầu như chẳng cần quan tâm đến package mà làm gì cho mệt, vì chúng có bao nhiêu lớp đâu. Nhưng khi bạn xây dựng các ứng dụng phức tạp hơn, có cả trăm lớp trong đó, như các bạn có thể thấy khi bước qua các project bên lập trình Android, thì việc tổ chức các lớp theo package lại rất hiệu quả.
Package Và Việc Tổ Chức Source Code Theo Thư Mục
Chúng ta vừa nói đến việc gom nhóm các lớp, khoan hãy tìm hiểu cách thức tạo ra package để làm việc như thế nào, mà hãy xem ngoài việc gom nhóm này ra, package còn có tác dụng gì khác không nhé.
Gom nhóm ở trên đây có nghĩa là khi nhìn vào Eclipe hay InteliJ, bạn sẽ thấy chúng cùng nằm trong một nhóm với nhau, như bài thực hành bên dưới sẽ nói rõ. Tuy nhiên việc gom nhóm này còn ảnh hưởng cả với các file .java được tạo ra ở ổ cứng. Ví dụ như nếu bạn tạo một package có tên là main, thì ở ổ cứng, nơi chứa đựng project của bạn, cũng sẽ có một thư mục là main. Bạn có thể tạo package bên trong package, khi đó các package lồng vào nhau được ngăn cách bởi dấu chấm, như bạn có thể thấy lớp Scanner nằm trong package java.util, thực chất đây là hai package java và util lồng vào nhau, như vậy thì trong ổ cứng cũng sẽ có hai thư mục java > util. Và cuối cùng thì lớp java nằm trong package nào thì tương tự ở ổ cứng, các file .java cũng nằm trong thư mục tương ứng.
Mục này không quá khó nên mình chỉ nói đến mà không có thực hành hay ví dụ cụ thể. Lát nữa đây khi thực hành tạo các lớp và package thì bạn hãy mở thư mục ở máy lên để kiểm chứng nhé.
Tạo Package Với Eclipse
Eclipse (hay sau này bạn lập trình Android với Android Studio cũng vậy) giúp cho chúng ta tạo ra và quản lý package một cách dễ dàng. Với Eclipse thì khi bạn tạo mới một project, sẽ chẳng có package nào cả. Điều này như mình nói ở trên, là với các project đơn giản, thì bạn không cần quan tâm lắm đến package. Và khi bạn tạo một class bên trong thư mục src/ như những bài thực hành trước, Eclipse sẽ gán vào trong cấu trúc lớp của chúng ta một cái tên “default package”, có nghĩa là chẳng có package gì ráo.

Vậy thì hôm nay chúng ta cùng tạo một project mới, hoàn hảo hơn, với cấu trúc rõ ràng được gom nhóm theo package, để biết được thực sự package giúp ích gì cho chúng ta nhé.
Thực Hành Tạo Mới Project Với Package
Bài thực hành hôm nay vẫn xoay quanh việc tính chu vi và diện tích các hình học, nhưng có nhiều điểm khác biệt. Thứ nhất, chúng ta cùng tạo mới project, với cái tên là PackageLearning để dễ làm việc. Thứ hai, chúng ta sẽ có nhiều lớp hơn để thử nghiệm việc tổ chức chúng theo package.
Đóng Project OOPLearning Lại
Nếu bạn còn đang mở Eclipse với project OOPLearning thì bạn nên đóng nó lại trước khi tạo mới PackageLearning. Đóng lại chứ không phải xóa đi nhé. Việc đóng một project lại giúp bạn có thể mở nó ra lại một cách nhanh chóng, vì nó vẫn nằm ở cửa sổ Package Explorer, có điều trạng thái của nó hơi khác thôi, ngoài ra khi đóng project lại, bạn sẽ dễ tập trung vào các project đang mở khác, trong trường hợp bạn có quá nhiều project cần quản lý.
Để đóng một project, bạn có thể click chuột phải vào project đó ở cửa sổ Package Explorer rồi chọn Close Project (như hình) hoặc chọn trên menu Project > Close Project. Thế là xong. Sau này bạn muốn mở project này lại thì lại click phải chuột vào nó, rồi chọn Open Project, hoặc tương tự với menu Project > Open Project.

Tạo Mới Project PackageLearning
Việc tạo mới project này không khác gì với các bài thực hành trước cả, các bạn cùng tạo một project với tên PackageLearning luôn nhé.
Hình sau là project PackageLearning mình mới tạo, bên cạnh project OOPLearning đã được đóng.

Tạo MainClass.java Nằm Trong Package main
Lần này bạn vẫn tạo một lớp chính chứa đựng phương thức main(), mình vẫn muốn đặt tên lớp chính này là MainClass.java. Tuy nhiên ở bài hôm nay, thay vì chỉ thiết lập thông số ở mục Name, và check vào public static void main(String[] args), thì bạn hãy thiết lập một cái tên cho mục Package (như hình dưới đây). Tên cho package bạn cũng đặt theo quy tắc đặt tên biến vậy, lần này mình đặt tên cho package chứa lớp MainClass này là main.

Sau khi nhấn Finish ở cửa sổ trên, bạn sẽ thấy một sự khác biệt, nơi mà với project OOPLearning hiển thị là “default package” thì nay lại là main.

Một khác biệt nữa, là với các lớp nằm trong một package, chúng sẽ có thêm một dòng khai báo package ở trên cùng của file. Như bạn nhìn thấy code của MainClass.java sau. Dòng khai báo package này phải khớp với tên package hiển thị ở cửa sổ Package Explorernhé. Sở dĩ mình nhắc điều này vì nếu vì một lý do nào đó, bạn sửa lại cấu trúc của các lớp ở Package Explorer, hay sửa tên của package ở cửa sổ này, mà quên sửa dòng khai báo package tương ứng ở file .java, thì hệ thống sẽ báo lỗi.
package main; public class MainClass { public static void main(String[] args) { // TODO Auto-generated method stub } }
Tạo Một Package Mới Với Tên shapes
Chúng ta tạm thời để một mình lớp MainClass vào bên trong package main thôi. Sau này nếu có các lớp khác với ý nghĩa dùng cho các mục đích quản lý chung chung thì sẽ thêm vào package này. Còn bây giờ là lúc chúng ta tạo ra các lớp hình học, mỗi hình như vậy sẽ có các thuộc tính và phương thức đặc thù. Và bởi vì các lớp hình học này có cùng một cấu trúc, nên chúng ta gom chúng vào chung một package, mình đặt tên package này là shapes.
Package shapes này sẽ ngang cấp với package main. Để tạo một package ngang cấp với main, bạn nên click chuột phải vào src/ (cha của main) và chọn New > Package. Hoặc đảm bảo vệt sáng ở thư mục src/ và chọn từ menu File > New > Package. Hình dưới là trường hợp click chuột phải vào src/.

Ở hộp thoại xuất hiện, bạn gõ shapes vào trong mục Name như hình dưới đây. Lưu ý là nếu bạn muốn tạo package là con của một package khác, thì ở mục Name này bạn cứ gõ theo kiểu package_cha.package_con, trong đó package_cha đã tồn tại, là được.

Sau khi nhấn Finish, bạn sẽ thấy package shapes xuất hiện trong cửa sổ quản lý Package Explorer. Tạm thời package shapes chưa có bất kỳ lớp nào bên trong đó, nên Eclipse mới dùng icon hơi khác với package main chút xíu.

Tạo Các Lớp Hình Học Bên Trong Package shapes
Chúng ta sẽ tạo môt lớp HinhTron, một lớp HinhChuNhat bên trong package shapes này. Bạn tự tạo nhé. Source code của hai hình mình để ở dưới, còn đây là hình ảnh khi mà bạn tạo đúng cấu trúc của bài thực hành hôm nay.

Nội dung của lớp HinhTron như sau. Bạn chú ý là mình có thêm các từ khóa public vào trước các phương thức trong các lớp, tạm thời bạn đừng quan tâm vội, đó là khả_năng_truy_cập của phương thức, mà mình sẽ nói cụ thể ở bài học sau.
package shapes; import java.util.Scanner; public class HinhTron { final float PI = 3.14f; float r; // Bán kính float cv; // Chu vi float dt; // Diện tích public void nhapBanKinh() { System.out.println("Hãy nhập vào Bán kính Hình tròn: "); Scanner scanner = new Scanner(System.in); r = scanner.nextFloat(); } public void tinhChuVi() { cv = 2 * PI * r; } public void tinhDienTich() { dt = PI * r * r; } public void inChuVi() { System.out.println("Chu vi Hình tròn: " + cv); } public void inDienTich() { System.out.println("Diện tích Hình tròn: " + dt); } }
Nội dung của lớp HinhChuNhat như sau. Tương tự, các phương thức ở lớp này cũng được gán khả năng truy cập là public.
package shapes; import java.util.Scanner; public class HinhChuNhat { float dai; // Chiều dài float rong; // Chiều rộng float cv; // Chu vi float dt; // Diện tích public void nhapChieuDai() { System.out.println("Hãy nhập vào Chiều dài Hình chữ nhật: "); Scanner scanner = new Scanner(System.in); dai = scanner.nextFloat(); } public void nhapChieuRong() { System.out.println("Hãy nhập vào Chiều rộng Hình chữ nhật: "); Scanner scanner = new Scanner(System.in); rong = scanner.nextFloat(); } public void tinhChuVi() { cv = 2 * (dai + rong); } public void tinhDienTich() { dt = dai * rong; } public void inChuVi() { System.out.println("Chu vi Hình chữ nhật: " + cv); } public void inDienTich() { System.out.println("Diện tích Hình chữ nhật: " + dt); } }
Sử Dụng Các Lớp HinhTron Và HinhChuNhat Từ MainClass
Vấn đề đến đây là khá dễ dàng với chúng ta. Bạn hãy thử quay lại phương thức main() của MainClass để yêu cầu người dùng nhập lần lượt các giá trị của hình tròn và hình chữ nhật thông qua khai báo các đối tượng từ hai lớp HinhTron và HinhChuNhat mà chúng ta vừa định nghĩa ra, rồi gọi đến các phương thức tính chu vi và diện tích, sau cùng thì gọi các phương thức in kết quả của chúng.
Có một điều khác biệt mà các bạn cần chú ý ở lớp MainClass này, đó là bởi vì MainClass ở khác package so với HinhTron và HinhChuNhat, nên khi gọi đến các lớp này, MainClass buộc phải import chúng ở đầu file, nếu không bạn sẽ thấy hệ thống báo lỗi. Kinh nghiệm để mà hệ thống tự động import các lớp từ các package khác thì mình đã nói ở Bài 7 khi mà chúng ta cần sử dụng lớp Scanner từ package java.util rồi nhé.
package main; import shapes.HinhChuNhat; import shapes.HinhTron; public class MainClass { public static void main(String[] args) { // Khai báo các đối tượng bằng từ khóa new HinhTron hinhTron = new HinhTron(); HinhChuNhat hinhChuNhat = new HinhChuNhat(); // Nhập dữ liệu vào cho hinhTron, tính chu vi, diện tích, và in ra hinhTron.nhapBanKinh(); hinhTron.tinhChuVi(); hinhTron.tinhDienTich(); hinhTron.inChuVi(); hinhTron.inDienTich(); // Ngăn cách các hình cho người dùng đỡ nhầm lẫn System.out.println("\n\n"); // Nhập dữ liệu vào cho hinhChuNhat, tính chu vi, diện tích, và in ra hinhChuNhat.nhapChieuDai(); hinhChuNhat.nhapChieuRong(); hinhChuNhat.tinhChuVi(); hinhChuNhat.tinhDienTich(); hinhChuNhat.inChuVi(); hinhChuNhat.inDienTich(); } }
Vậy là kiến thức về package đã xong, package này sẽ ảnh hưởng nhiều đến khả_năng_truy_cập vào các thuộc tính và phương thức của lớp ở bài học sau.
Cảm ơn bạn đã đọc các bài viết của Yellow Code Books. Bạn hãy ủng hộ blog bằng cách:
– Đánh giá 5 sao ở mỗi bài viết nếu thấy thích.
– Comment bên dưới mỗi bài viết nếu có thắc mắc.
– Để lại địa chỉ email của bạn ở thanh bên phải để nhận được thông báo sớm nhất khi có bài viết mới.
– Chia sẻ các bài viết của Yellow Code Books đến nhiều người khác.
– Ủng hộ blog theo hướng dẫn ở thanh bên phải để blog ngày càng phát triển hơn.
Bài Kế Tiếp
Chúng ta sẽ nói đến việc sử dụng các phương thức khởi tạo trong Java, để xem chúng khác với phương thức bình thường như thế nào, mục đích và lợi ích mà chúng mang lại trong việc tổ chức các lớp và đối tượng của chúng ta như thế nào nhé.
Nếu người nhập mà lỡ nhập vào chiều rộng hình chữ nhật lớn hơn chiều dài thi sao ad nhỉ? cái này có cần phải lồng điều kiện vào cho phù hợp ko?
Cái này phải tự người lập trình đặt điều kiện để người dùng không thể nhập ngược lại thôi bạn nhé.
học hết 50 bài này là đủ hết kiến thức cơ bản và nâng cao của java đúng không anh?
phần còn lại xử lí thì dựa vào tư duy của mình đúng không ạ.