99 Ngày Java — Ngày 10: Phương thức & truyền tham số
Chín ngày qua, mọi code của chúng ta đều chen chúc trong main — tính điểm cũng main, đảo mảng cũng main. Hôm nay ta học cách đóng gói logic thành phương thức (method): đặt tên cho một việc, gọi lại trăm lần không copy-paste. Kèm theo là hai chủ đề phỏng vấn kinh điển: overloading — nhiều method trùng tên, và sự thật đằng sau câu thần chú "Java luôn pass-by-value" mà Ngày 09 đã hứa.

Khai báo method: đặt tên cho một việc
Method là một cỗ máy nhỏ có tên: nhận nguyên liệu (tham số), làm đúng một việc, và có thể trả về thành phẩm (giá trị trả về). Cú pháp gồm bốn mảnh:
// [modifier] [kiểu trả về] [tên](tham số) { thân — và return nếu có trả về }
static int tong(int a, int b) { // nhận 2 int, TRẢ VỀ int
return a + b; // return: trả kết quả VÀ thoát method
}
static void chao(String ten) { // void = không trả về gì
System.out.println("Chào " + ten + "!");
// return; — được phép, chỉ để thoát sớm
}
public static void main(String[] args) {
int kq = tong(3, 4); // GỌI: đối số 3, 4 → tham số a, b
chao("Mọt Dev"); // 7 được gán vào kq
System.out.println(tong(kq, 10)); // 17 — kết quả dùng trực tiếp được
}Tham số (parameter) là biến khai trong ngoặc; đối số (argument) là giá trị thật lúc gọi —
3và4rót vàoavàbtheo đúng thứ tự.returnlàm hai việc cùng lúc: trả kết quả và thoát ngay — code saureturnkhông bao giờ chạy. Method khai kiểu trả về thì mọi nhánh (nhớ if–else Ngày 06) đều phải dẫn tới mộtreturn.Tên method dùng camelCase động từ:
tinhTong,inBangDiem— đọc phát biết làm gì. Một method chỉ nên làm một việc; dài quá một màn hình là dấu hiệu nên tách.Khoan thắc mắc chữ
static— nó nghĩa là "thuộc về lớp, gọi không cần đối tượng". Ngày 11–18 sẽ trả lời trọn vẹn; tạm thời cứ viếtstaticcho method gọi từmain.
Overloading — trùng tên, khác chữ ký
Java cho phép nhiều method cùng tên miễn danh sách tham số khác nhau (khác số lượng hoặc khác kiểu) — gọi là overloading. Compiler nhìn đối số lúc gọi để chọn bản khớp nhất, ngay tại thời điểm biên dịch:
static int max(int a, int b) { return a > b ? a : b; }
static double max(double a, double b) { return a > b ? a : b; }
static int max(int a, int b, int c) { return max(max(a, b), c); }
max(3, 7) // → bản int: 7
max(2.5, 1.5) // → bản double: 2.5
max(1, 9, 4) // → bản 3 tham số: 9
max(3, 7.0) // → bản double! int 3 được widening (Ngày 05) thành 3.0
// ✗ KHÔNG phải overload — chỉ khác kiểu trả về thì compiler chịu:
// static double max(int a, int b) { ... } → lỗi biên dịch!Bộ "tên + danh sách kiểu tham số" gọi là chữ ký (signature) — kiểu trả về không thuộc chữ ký, nên chỉ khác kiểu trả về là lỗi biên dịch.
Trường hợp
max(3, 7.0)cho thấy overloading bắt tay với ép kiểu tự động Ngày 05: không có bản(int, double)nên3được widening lêndouble.Bạn đã dùng overloading từ Ngày 01 mà không biết:
printlncó hơn 10 bản — nhậnint,String,char[]… đều in được là nhờ vậy.Còn "một method nhận bao nhiêu đối số cũng được" kiểu
String.joinNgày 09? Đó là varargs — hẹn Ngày 25.
Pass-by-value — sự thật đằng sau câu thần chú
Câu hỏi phỏng vấn quốc dân: "Java pass-by-value hay pass-by-reference?" Đáp án gọn: luôn luôn pass-by-value — mọi đối số đều bị copy khi rót vào tham số. Nhưng cái được copy là gì mới là chỗ thú vị: với primitive là giá trị, còn với object (mảng Ngày 08, chuỗi Ngày 09…) là tham chiếu — và bản sao tham chiếu vẫn trỏ về cùng một đối tượng:
static void tangSo(int x) { x = x + 100; } // sửa BẢN SAO
static void suaMang(int[] m) { m[0] = 99; } // sửa NỘI DUNG chung
static void thayMang(int[] m) { m = new int[] { 7 }; } // gán lại BẢN SAO tham chiếu
public static void main(String[] args) {
int so = 1;
tangSo(so);
System.out.println(so); // 1 — primitive: copy GIÁ TRỊ, bản gốc bình an
int[] mang = { 1, 2, 3 };
suaMang(mang);
System.out.println(mang[0]); // 99 — copy THAM CHIẾU: hai bên nhìn CÙNG mảng!
thayMang(mang);
System.out.println(mang[0]); // vẫn 99 — gán lại chỉ đổi bản sao tham chiếu
}Sửa nội dung qua bản sao tham chiếu → bản gốc thấy thay đổi (cùng nhìn một mảng trên heap).
Gán lại tham số → chỉ xoay bản sao sang chỗ khác, bản gốc không suy chuyển — vì thế không thể viết method "swap hai biến int" trong Java!
Ghép với Ngày 09:
Stringbất biến nên truyền đi đâu cũng an toàn tuyệt đối — không ai "sửa nội dung" được, chỉ có thể gán lại bản sao của họ.
Phạm vi biến (scope)
Method sinh ra ranh giới sống cho biến: biến khai ở đâu thì chỉ sống trong cặp ngoặc nhọn đó — gọi là biến local:
public static void main(String[] args) {
int diem = 9; // sống từ đây đến hết main
if (diem >= 5) {
String xepLoai = "Đậu"; // sống TRONG khối if — ra ngoài là biến mất
System.out.println(xepLoai);
}
// System.out.println(xepLoai); // ✗ lỗi biên dịch: ngoài phạm vi!
for (int i = 0; i < 3; i++) { } // i chỉ sống trong vòng for (Ngày 07)
// System.out.println(i); // ✗ i đã "hết đời"
int chuaGan;
// System.out.println(chuaGan); // ✗ biến local KHÔNG có giá trị mặc định!
}Tham số cũng là biến local của method —
xtrongtangSochết khi method kết thúc, đó chính là lý do pass-by-value "vô hại" ở trên.Biến local không có giá trị mặc định — khác với mảng Ngày 08 (phần tử tự về
0). Dùng trước khi gán là lỗi biên dịch, không phải lỗi runtime.Phạm vi càng hẹp càng tốt: khai biến sát nơi dùng, vòng đời ngắn thì bug ít chỗ trốn.
Bài tập nhỏ
Viết
static boolean laSoNguyenTo(int n)rồi dùng nó in mọi số nguyên tố dưới 100 (vòng lặp Ngày 07 tái xuất).Overload
dienTich(double canh)(hình vuông) vàdienTich(double dai, double rong)(chữ nhật) — gọi cả hai.Viết
static void tangLuong(double[] luong, double phanTram)tăng lương cả mảng — giải thích vì sao bản gốc thay đổi dù Java pass-by-value.Thử viết method "hoán đổi hai biến
int" — chứng kiến nó bất lực, rồi giải thích bằng bài học hôm nay.
Kết luận
Bạn vừa có công cụ tổ chức code đầu tiên: method — khai báo với tham số và giá trị trả về, overload để một tên phục vụ nhiều kiểu dữ liệu, hiểu pass-by-value đủ sâu để trả lời phỏng vấn lẫn tránh bug, và scope giữ biến sống đúng chỗ. Đây cũng là viên gạch cuối của Giai đoạn 1 — nền tảng ngôn ngữ. Từ Ngày 11, ta bước vào vùng đất lớn nhất của Java: lập trình hướng đối tượng — bắt đầu với lớp và đối tượng, nơi dữ liệu và method về chung một nhà. Hẹn gặp lại!
Site Admin
Engineer and writer. Building things with TypeScript and distributed systems.
Bình luận (0)
Bạn cần đăng nhập bằng Google để bình luận.
Hãy là người bình luận đầu tiên.


