Java Bài 29: Nạp Chồng Phương Thức (Overloading)

Nội dung bài viết

Toggle
  • Nạp Chồng Phương Thức (Overloading) Là Gì?
  • Nạp Chồng Phương Thức Có Tác Dụng Gì?
    • Thực Hành Xây Dựng Ứng Dụng Tính Lương Cho Nhân Viên
      • Yêu Cầu Chương Trình
      • Sơ Đồ Lớp
      • Xây Dựng Các Lớp
  • Kết Luận
Rate this item:1.002.003.004.005.00Submit Rating Rating: 5.0/5. From 48 votes. Please wait...

Được chỉnh sửa ngày 22/12/2022.

Chào mừng các bạn đã đến với bài học Java số 29. Bài học về Nạp chồng phương thức (Overloading). Đây là bài học trong chuỗi bài về lập trình ngôn ngữ Java của Yellow Code Books.

Nếu bạn nhớ, chúng ta đã học về overriding. Hôm nay bạn lại được biết thêm về overloading. Cẩn thận coi chừng nhầm lẫn nha bạn. Overriding, overloading, over, and over…

Mình đùa tí thôi, mình giúp các bạn nhớ lại một tí như sau.

  • Overriding là cái sự lớp con ghi đè phương thức của lớp cha.
  • Overloading là nạp chồng phương thức.

Mời các bạn cùng đến với bài học hôm nay. Bài học sẽ giúp bạn nắm được khái niệm overloading là gì. Bên cạnh đó nó còn giúp bạn đừng bị nhầm lẫn giữa overridingoverloading nữa đấy.

Nạp Chồng Phương Thức (Overloading) Là Gì?

Đây là một khái niệm khá hay trong OOP. Overloading cho phép một lớp có khả năng định nghĩa ra nhiều phương thức có cùng tên, nhưng khác nhau về tham số truyền vào. Phương thức ở đây có bao gồm luôn constructor nhé.

Kỹ thuật overloading làm tăng tính sử dụng cho các phương thức bên trong một lớp.

Bạn thử nhìn vào ví dụ sau đây.

public class HinhTron { private float banKinh; // Constructor không tham số public HinhTron() { this.banKinh = 0; } // Constructor một tham số banKinh public HinhTron(float banKinh) { this.banKinh = banKinh; } // Phương thức không tham số public float tinhChuVi() { // return kết quả tính chu vi } // Phương thức một tham số donVi public float tinhChuVi(int donVi) { // return kết quả tính chu vi dựa vào tham số donVi truyền vào } }

Như mình có nói trên kia rằng, overloading cho phép bạn khai báo nhiều phương thức hoặc nhiều constructor trong một lớp có tên trùng nhau, nhưng khác tham số. Bạn đã thấy ví dụ trên khai báo hai constructor trùng tên là HinhTron() và hai phương thức trùng tên tinhDienTich() rồi đó. Đó chính là overloading, nó giống như bạn cung cấp các lớp constructor và phương thức trùng tên (khác tham số), chúng như được xếp chồng lên nhau, hay nạp chồng lên nhau.

Bạn cũng đã thấy, rõ ràng overridingoverloading dễ nhầm lẫn nhau ở chỗ, rằng chúng đều nói đến sự đặt tên trùng nhau của các phương thức. Nhưng overriding là nguyên tắc đặt tên phương thức của lớp con trùng với tên phương thức của lớp cha (đồng thời các tham số truyền vào cũng phải trùng nhau). Còn overloading lại bắt buộc đặt tên các phương thức trong một lớp trùng nhau (không liên quan gì đến lớp cha cả, và các tham số truyền vào các phương thức này phải khác nhau).

Đau đầu đúng không. Bạn sẽ quen nhanh thôi khi thao tác nhiều với hai kỹ thuật này.

Nạp Chồng Phương Thức Có Tác Dụng Gì?

Theo như mình thấy. Nếu bạn áp dụng overloading vào một lớp, tức xây dựng nhiều phương thức trùng tên trong một lớp. Nó sẽ không có tác dụng ngay cho lớp đó, chẳng hạn như nó không giúp code của lớp đó gọn gàng, hay rõ ràng hơn để bạn dễ code hay dễ quản lý gì đâu, đôi khi nó gây ra một sự xáo trộn nhất định về mặt tổ chức bên trong lớp đó, nếu như bạn có quá nhiều các phương thức trùng tên.

Nhưng overloading lại phát huy tác dụng rất lớn khi bạn gọi đến chúng từ các lớp khác. Nó làm tăng tính sử dụng của lớp có dùng kỹ thuật overloading.

Mình sẽ cho bạn một vài dẫn chứng, bạn có nhớ ở bài học về cách sử dụng StringBuffer (hay StringBuilder) không, khi đó constructor của các lớp này được nạp chồng khiến cho khi bạn khởi tạo chúng, bạn nhận ra các constructor như hình sau.

Nạp chồng constructor đối với lớp StringBuffer
Nạp chồng constructor đối với lớp StringBuffer

Hay mỗi khi gọi đến phương thức để in dữ liệu ra console, bạn có thấy rất nhiều các phương thức println() được nạp chồng cùng tên hay không. Như hình sau.

Nạp chồng phương thức println()
Nạp chồng phương thức println()

Bạn thấy đó, với việc nạp chồng nhiều constructor hay phương thức như trên giúp làm tăng tính hiệu quả sử dụng của lớp StringBuffer cũng như các phương thức bên trong System.out. Cụ thể như với System.out, khi này thì các phương thức nạp chồng println() đã “bao sô” hết tất cả các tham số có thể có rồi, do đó bạn có thể yêu cầu phương thức này xuất ra console bất cứ dữ liệu nào mà bạn muốn, bởi chỉ một phương thức println(), nó đều làm được mà không ỏng ẹo gì cả, rất dễ nhớ và vận dụng đúng không nào. Nếu không có overloading, chắc chắn trường hợp này bạn phải cần rất nhiều phương thức cho từng trường hợp, như printlnInt(), printlnChar(), printlnLong(),… đúng không, vậy thì rối quá.

Quay lại lớp HinhTron mà bạn vừa thử nghiệm trên kia, nếu như ở đâu đó có khai báo lớp này, bạn sẽ thấy danh sách nạp chồng constructor của nó như sau.

Nạp chồng constructor đối với lớp HinhTron

Hay khi gọi đến các phương thức nạp chồng tinhChuVi() bên trong lớp này, bạn sẽ thấy sự gợi ý đến các phương thức này như hình bên dưới. Thật là “chuyên nghiệp”.

Nạp chồng phương thức tinhChuVi()
Nạp chồng phương thức tinhChuVi()

Bạn đã hiểu được hiệu quả khi dùng kỹ thuật overloading rồi dùng không nào. Giờ thì code thôi.

Thực Hành Xây Dựng Ứng Dụng Tính Lương Cho Nhân Viên

Đã lâu rồi chúng ta không làm cái gì đó cho nó mới mẻ hay hoành tráng. Vậy thì bài hôm nay bạn hãy cố gắng vận động gân cốt một tí. Mời bạn mở InteliJ lên và thử xây dựng project nho nhỏ sau. Bạn hãy đọc yêu cầu rồi cố gắng vận dụng hết tất cả các kiến thức về OOP từ trước tới giờ vô bài thực hành luôn nhé.

Yêu Cầu Chương Trình

Ứng dụng của chúng ta phục vụ một công ty nhỏ. Với một số nguyên tắc sau.

  • Công ty này có hai loại nhân viên, đó là nhân viên toàn thời gian và nhân viên thời vụ.
  • Nhân viên toàn thời gian là lính sẽ hưởng lương 10 củ một tháng. Nhân viên toàn thời gian là sếp sẽ hưởng lương 20 củ một tháng.
  • Nhân viên toàn thời gian nếu làm thêm ngày nào thì sẽ được cộng thêm 800k mỗi ngày, bất kể chức vụ.
  • Nhân viên thời vụ cứ làm mỗi giờ được 100k, không phân biệt chức vụ gì cả. Làm nhiều thì hưởng nhiều.

Vậy thôi, ứng dụng sẽ cho phép nhập vào từng nhân viên. Mỗi nhân viên có tên nhân viên. Có loại nhân viên toàn thời gian hay bán thời gian. Nhân viên toàn thời gian thì là nhân viên lính hay nhân viên sếp, có làm thêm ngày nào không. Nhân viên thời vụ thì làm được mấy giờ. Cuối cùng dựa vào các thông tin đó, sẽ xuất ra màn hình lương tương ứng.

Sơ Đồ Lớp

Do yêu cầu chương trình có phần phức tạp, nên chỉ có thể giải thích rõ ràng nhất thông qua sơ đồ lớp mà thôi.

Sơ đồ lớp
Sơ đồ lớp

Bạn có thể thấy rằng, sơ đồ này có thêm nhiều thông tin hơn so với những ngày đầu bạn mới làm quen. Để mình giải thích một số thông tin bổ sung này.

– Thông tin package được thể hiện ở dưới tên lớp, với font chữ nhỏ hơn. Như vậy nhìn sơ đồ chúng ta thấy các lớp NhanVienNhanVienFullTime và NhanVienPartTime nằm trong cùng package model. Lớp Configs nằm trong package util.– Khả năng truy cập của các thuộc tính và phương thức nay rõ ràng hơn. Khi đó dấu (-) là private, dấu (+) là public, và dấu (#) là protected.– Hằng số là các giá trị được viết in hoa.– Còn giá trị static sẽ được gạch chân, như các thuộc tính trong lớp Configs.

Như vậy sơ đồ của chúng ta ngày càng rõ ràng hơn rồi đó.

Xây Dựng Các Lớp

Đến đây bạn tự code được rồi đó.

Đầu tiên là lớp Configs để lưu các giá trị tĩnh, như mức lương tháng, lương ngày, lương giờ,…

package util; public class Configs { // Loại nhân viên public static final int NHAN_VIEN_SEP = 1; public static final int NHAN_VIEN_LINH = 2; // Lương nhân viên public static final long LUONG_NHAN_VIEN_FULL_TIME_SEP = 20000000; // Lương tháng của sếp public static final long LUONG_NHAN_VIEN_FULL_TIME_LINH = 10000000; // Lương tháng của lính public static final long LUONG_LAM_THEM_MOI_NGAY = 800000; // Làm thêm mỗi ngày của nhân viên toàn thời gian được 800 k public static final long LUONG_NHAN_VIEN_PART_TIME_MOI_GIO = 100000; // Lương nhân viên thời vụ mỗi giờ 100 k }

Kế đến là lớp cha NhanVien.

package model; public class NhanVien { protected String ten; protected long luong; public NhanVien() { } public NhanVien(String ten) { this.ten = ten; } protected String loaiNhanVien() { // Lớp con phải override để lo vụ loại nhân viên này return ""; } public void xuatThongTin() { System.out.println("===== Nhân viên: " + ten + " ====="); System.out.println("- Loại nhân viên: " + loaiNhanVien()); System.out.println("- Lương: " + luong + " VND"); } }

Rồi đến hai lớp con NhanVienFullTime và NhanVienPartTime.

package model; import util.Configs; /** * NhanVienFullTime chính là nhân viên toàn thời gian */ public class NhanVienFullTime extends NhanVien { private int ngayLamThem; // Ngày làm thêm của nhân viên private int loaiChucVu; // Chức vụ là lính hay sếp public NhanVienFullTime(String ten) { super(ten); this.loaiChucVu = Configs.NHAN_VIEN_LINH; // Mặc định là lính } public NhanVienFullTime(String ten, int ngayLamThem) { super(ten); this.ngayLamThem = ngayLamThem; this.loaiChucVu = Configs.NHAN_VIEN_LINH; // Mặc định là lính } public void setLoaiChucVu(int loaiChucVu) { this.loaiChucVu = loaiChucVu; } @Override public String loaiNhanVien() { if (loaiChucVu == Configs.NHAN_VIEN_LINH) { return "Lính toàn thời gian" + (ngayLamThem > 0 ? " (có làm thêm ngày)":""); } else { return "Sếp toàn thời gian" + (ngayLamThem > 0 ? " (có làm thêm ngày)":""); } } public void tinhLuong() { if (loaiChucVu == Configs.NHAN_VIEN_LINH) { luong = Configs.LUONG_NHAN_VIEN_FULL_TIME_LINH + ngayLamThem * Configs.LUONG_LAM_THEM_MOI_NGAY; } else if (loaiChucVu == Configs.NHAN_VIEN_SEP) { luong = Configs.LUONG_NHAN_VIEN_FULL_TIME_SEP + ngayLamThem * Configs.LUONG_LAM_THEM_MOI_NGAY; } } } package model; import util.Configs; /** * NhanVienPartTime chính là nhân viên thời vụ */ public class NhanVienPartTime extends NhanVien { private int gioLamViec; // Tổng số giờ làm việc của nhân viên public NhanVienPartTime(String ten, int gioLamViec) { this.ten = ten; this.gioLamViec = gioLamViec; } @Override public String loaiNhanVien() { return "Nhân viên thời vụ"; } public void tinhLuong() { luong = Configs.LUONG_NHAN_VIEN_PART_TIME_MOI_GIO * gioLamViec; } }

Và đây là lời gọi đến từ main().

package main; import model.NhanVienFullTime; import model.NhanVienPartTime; import util.Configs; public class MainClass { public static void main(String[] args) { // Công ty có 3 nhân viên toàn thời gian, trong đó có 1 sếp, sếp không làm thêm ngày nào NhanVienFullTime sep = new NhanVienFullTime("Trần Văn Sếp"); sep.setLoaiChucVu(Configs.NHAN_VIEN_SEP); NhanVienFullTime linh1 = new NhanVienFullTime("Nguyễn Văn Lính"); // Không làm thêm ngày nào NhanVienFullTime linh2 = new NhanVienFullTime("Lê Thị Lính", 3); // Làm thêm 3 ngày // Công ty đang thuê 1 nhân viên thời vụ NhanVienPartTime thoiVu = new NhanVienPartTime("Phan Thị Thời Vụ", 240); // Cô ấy siêng làm lắm // Tính lương cho nhân viên sep.tinhLuong(); linh1.tinhLuong(); linh2.tinhLuong(); thoiVu.tinhLuong(); // In thông tin nhân viên sep.xuatThongTin(); linh1.xuatThongTin(); linh2.xuatThongTin(); thoiVu.xuatThongTin(); } }

Đây là kết quả khi bạn thực thi chương trình lên.

===== Nhân viên: Trần Văn Sếp ===== - Loại nhân viên: Sếp toàn thời gian - Lương: 20000000 VND ===== Nhân viên: Nguyễn Văn Lính ===== - Loại nhân viên: Lính toàn thời gian - Lương: 10000000 VND ===== Nhân viên: Lê Thị Lính ===== - Loại nhân viên: Lính toàn thời gian (có làm thêm ngày) - Lương: 12400000 VND ===== Nhân viên: Phan Thị Thời Vụ ===== - Loại nhân viên: Nhân viên thời vụ - Lương: 24000000 VND Kết Luận

Chúng ta vừa trải qua một kiến thức thú vị nữa của Java, kiến thức về nạp chồng phương thức, hay còn gọi overloading. Qua bài học thì bạn cũng đã nắm rõ và phân biệt tốt thế nào là overriding và thế nào là overloading rồi đúng không nào.

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 cùng làm quen với một trong những đặc tính nổi trội khác trong OOP nữa, đó là tính đa hình, hay còn được gọi với một cái tên xa lạ, khó nhớ, và cũng chẳng thân thương gì ráo: polymorphism.

← Java Bài 28: Từ Khóa static Java Bài 30: Đa Hình (Polymorphism) →

Từ khóa » Ví Dụ Về Overloading