Menu

Java: Tham chiếu và tham trị

Java truyền tham số vào phương thức (hàm) theo kiểu tham số hay tham trị? Một câu hỏi rất dễ tìm câu trả lời trên Google. Và câu trả lời tất nhiên là tham trị! Nhưng vẫn có rất nhiều junior đã, đang nhầm lẫn và cảm thấy nghi ngờ. Bài viết này sẽ đưa ra và ví dụ minh họa để cho ai vẫn đang nhầm lẫn có một cái nhìn rõ hơn.

Java truyền tham số theo tham trị!

Để kiểm chứng lại kết quả trên Google có đúng là Java truyền tham số vào phương thức theo kiểu tham trị hay không. Ta sẽ làm một ví dụ rất đơn giản, đó là phương thức đổi giá trị của hai biến (swap).

Hãy dịch và chạy thử file SwapInt.java. Bạn thấy gì nào?
Giá trị trước khi truyền vào phương thức swap là c = 1d = 2. Sau khi truyền vào phương thức swap thì giá trị của nó cũng không thay đổi.
Hoặc ví dụ với trường hợp tham số truyền vào là object (không phải kiểu nguyên thủy) như sau:
Hãy dịch và chạy đoạn code trên đi (bạn cần thêm lớp Point), kết quả thế nào? Phương thức swap vẫn không đổi giá trị cho nhau đúng không?
Vậy hóa ra Google nói đúng, Java truyền tham số vào phương thức theo kiểu tham trị. Câu chuyện rõ ràng như vậy, sao vẫn còn nhiều người nhầm lẫn và nghi ngờ?

Trường hợp nhầm lẫn

Hãy xem ví dụ sau đây (cái mà một số junior vẫn hay nhầm nhất):
Bạn hãy dịch, chạy file SwapPointRef.java đi và cho tôi biết kết quả. Kết quả thế nào? Rõ ràng là khác 2 lần trước đúng không? Nội dung in ra màn hình đã có sự xáo trộn rồi, có vẻ là chúng đổi chỗ cho nhau thật.
Khoan đã, ta sẽ xem lại phương thức swap của lớp SwapPointRef với SwapPoint SwapInt xem có gì khác nhau không.

Mình gom 3 phương thức swap lại gần nhau cho dễ nhìn. Bạn đã nhìn thấy sự khác biệt chưa?
Nếu bạn vẫn chưa nhận thấy sự khác biệt thì mình sẽ chỉ cho bạn thấy ngay. Đối với phương thức swap của lớp SwapPoint SwapInt, mình đổi chỗ hai tham số truyền vào còn với phương thức swap ở lớp SwapPointRef mình chỉ "đổi chỗ" giá trị của hai trường của hai tham số.
À đúng rồi nhỉ? Nhưng tôi tin bạn vẫn còn một thắc mắc đó là: Nếu như Java truyền tham số theo kiểu tham trị (tức là truyền giá trị) thì các tham số được truyền vào là bảo sao (copy) của dữ liệu. Việc thay đổi trên dữ liệu copy đó thì sao lại ảnh hưởng để nội dung của dữ liệu gốc được?
Để trả lời câu hỏi trên, bạn hãy quan sát hình vẽ dưới đây:
  • Hình chữ nhật thể hiện cho mối đối tượng của lớp (trong hình là một đối tượng của lớp Point).
  • Mỗi hình tròn thể hiện cho một "tham chiếu" để đối tượng (có thể hiểu đây là những cái tên của một người).

Để rõ hơn bạn hãy xem ví dụ sau:

Chạy ví dụ này và bạn thấy rằng, dù bạn thay đổi một nội dung của bất cứ "cái tên nào" thì tất cả nội dung của các "cái tên" khác cũng đều ảnh hưởng theo (hiểu đơn giản như sau: ở nhà gọi là cu Tèo, đến lớp gọi là Nam, đi làm gọi là Bắc, nếu Bắc trúng xổ số thành tỷ phú thì cu Tèo hay thằng Nam cũng là tỷ phú.).
Như vậy, việc đổi chỗ trong hàm swap của lớp SwapInt SwapPoint thực chất chỉ là đổi chỗ hai "cái tên". Những cái tên sẽ được tạo ra khi ta gọi phương thức và mất đi khi phương thức kết thúc. Tuy nhiên, tại một thời điểm cụ thể, "mỗi cái tên" sẽ ám chỉ một đối tượng cụ thể (hoặc là không nếu ta gán tên đó với giá trị null) nên khi tác động vào nội dung của mỗi cái tên là ta sẽ tác động vào nội dung của đối tượng.
Do đó, một lưu ý quan trọng là khi bạn truyền một đối tượng vào hàm thì hãy cẩn thận, rất có thể nội dung của đối tượng đã bị thay đổi khi gọi hàm.

Kết luận

Java truyền tham số theo kiểu tham biến hay tham trị là một câu hỏi rất dễ tìm câu trả lời. Tuy nhiên, với junior thì không phải cái nào cũng dễ tìm. Hi vọng bài viết giúp các junior hiểu sâu sắc hơn vấn đề này.

Không có nhận xét nào:

Đăng nhận xét