15-05-2024
Nhắc lại một chút về các kiểu dữ liệu trong java:
Trong JAVA có 2 loại kiểu dữ liệu: cơ bản và tham chiếu :
– Kiểu cơ bản : Số nguyên, số thực, kí tự , logic
– Kiểu tham chiếu : Kiểu mảng, kiểu lớp đối tượng Class, kiểu Interface
kiểu dữ liệu tham chiếu (reference data type) là một loại dữ liệu mà giá trị của nó là một tham chiếu hoặc địa chỉ tới một đối tượng trong bộ nhớ heap. Không giống như các kiểu dữ liệu nguyên thủy (primitive data types) chứa trực tiếp giá trị của chúng, các kiểu dữ liệu tham chiếu lưu trữ địa chỉ của vùng nhớ nơi đối tượng thực sự nằm.
Khi khai báo biến kiểu cơ bản trong java:
Vd:
int x = 10;
Khi đoạn code trên được chạy ngoài việc lưu trữ giá trị, hệ thống cũng tạo ra một địa chỉ bộ nhớ cho x. Địa chỉ này là một con số duy nhất xác định vị trí của vùng nhớ nơi giá trị 10 được lưu trữ. Bạn có thể nghĩ về địa chỉ bộ nhớ như một "địa chỉ nhà" giúp hệ thống biết được nơi nào trong bộ nhớ đang chứa giá trị của x.
Sơ đồ diễn tả việc khai báo biến x
Trong sơ đồ trên giá trị 11AABBCCDD chính là địa chỉ của vùng nhớ của biến x và lưu trữ giá trị là 10
Khi khai báo biến kiểu tham chiếu trong java:
Kiểu tham chiếu được dùng để lưu một giá trị tham chiếu (địa chỉ ô nhớ) của một đối tượng nhưng không lưu trữ đối tượng đó.
Bởi vì kiểu tham chiếu chỉ lưu địa chỉ của ô nhớ của biến thay vì lưu giá trị của biến, nên khi gán một biến tham chiếu cho một biến khác thì nó không copy data mà nó chỉ copy địa chỉ tham chiếu.
Nên cả 2 biến sẽ cùng tham chiếu đến một địa chỉ giống nhau trên bộ nhớ Heap.
Sơ đồ diễn tả khai báo kiểu dữ liệu tham chiếu
Ô màu xanh dương chính là địa chỉ của biến, chỉ đến giá trị của nó là ô màu đỏ, ô màu đỏ sẽ lại chứa các địa chỉ dẫn đến các giá trị là địa chỉ ô màu đỏ lưu trữ mà ở đây là chuỗi “Kitty”
Khái niệm truyền tham chiếu và truyền tham trị
"Tham chiếu" (pass by reference) và "tham trị" (pass by value) là hai cơ chế khác nhau để truyền tham số vào một phương thức (method) hoặc hàm (function). Sự khác biệt chính giữa chúng nằm ở cách thức mà giá trị của tham số được truyền và cách thay đổi giá trị của tham số bên trong phương thức ảnh hưởng đến biến gốc bên ngoài phương thức.
Tham trị: Trong cơ chế tham trị, một bản sao của giá trị của biến được truyền vào phương thức. Điều này có nghĩa là các thay đổi đối với tham số bên trong phương thức sẽ không ảnh hưởng đến biến gốc bên ngoài phương thức.
Tham chiếu: Truyền tham chiếu là một cơ chế mà thông qua đó một hàm (hoặc phương thức) nhận trực tiếp địa chỉ bộ nhớ của biến thay vì một bản sao của giá trị biến đó. Điều này có nghĩa là bất kỳ thay đổi nào được thực hiện trên tham số bên trong hàm sẽ ảnh hưởng trực tiếp đến biến gốc bên ngoài hàm.
Vậy còn trong java thì sao?
Tham trị trong java:
Việc chuyền tham trị trong java cũng giống như trong khái niệm được nói ở trên.
Hãy nhìn vào đoạn code sau để hiểu rõ hơn.
Ở phương thức main(), chúng ta cũng bắt đầu với việc khai báo x = 10. Sau đó chúng ta truyền biến x này dưới dạng tham số vào cho phương thức Sum(). Thế nhưng vào bên trong Sum(), tham số lúc này cũng có tên là x và chúng ta còn gán lại giá trị mới cho x nữa, là x + 1. Và sau khi Sum() kết thúc, câu lệnh in x ra sẽ in ra số 10 chứ không hề tăng giá chị của x lên 1.
Khi truyền biến x vào hàm Sum() nó chỉ đơn giản là sao chép giá trị của biến x được truyền vào và gán cho giá trị biến x của hàm Sum(). x trước khi truyền vào trong phương thức Sum() mang giá trị 10. Còn x bên trong Sum() không phải x ở ngoài, nó chỉ là một biến khác được sao chép ra, cũng mang tên x, cũng mang giá trị 10, nhưng không còn là x ở ngoài nữa. Do đó dù bên trong Sum() chúng ta có thay đổi x như thế nào thì cũng không ảnh hưởng với x bên ngoài.
Tham chiếu trong java:
Đầu tiên phải khẳng định rằng Java không hề hỗ trợ truyền tham chiếu Java chỉ hỗ trợ truyền tham số kiểu Tham trị mà thôi. Bởi không có một cách nào để ta làm điều đó cả. Ví dụ với một ngôn ngữ hỗ trợ truyền tham chiếu như C:
Trong ngôn ngữ C ta có thể dùng int* x làm tham số cho hàm và dùng &x để chuyền cho hàm đối số có giá trị là địa chỉ của biến x. Ở ví dụ trên giá trị của x ban đầu là 10 nhưng sau khi gọi hàm Sum() giá trị của x đã tăng lên là 11 vì trong hàm Sum() đã làm thay đổi giá trị của biến x
Thường thì chúng ta sẽ nghĩ rằng kiểu dữ liệu cơ sở được truyền theo tham trị, kiểu dữ liệu tham chiếu được truyền theo tham chiếu. Nhưng đó hoàn toàn là một sự nhầm lần
Khi các bạn truyền một biến có kiểu object vào một hàm thì lúc đó có nghĩa ta đã truyền giá trị của biến đó để sử dụng trong hàm, chứ không phải truyền đối tượng được biến đó tham chiếu tới. Vậy nên việc thay đổi giá trị của biến có kiểu object này bằng cách gán cho một biến kiểu object khác thì object được tham chiếu đến lúc đầu không bị ảnh hưởng, chỉ khi sử dụng các method của chính các object được tham chiếu này thì dữ liệu của object mới được thay đổi sau khi ra khỏi hàm.
Hãy xem ví dụ sau
Trong phương thức changeValue2, obj.value = 20; thay đổi giá trị của thuộc tính value của đối tượng mà obj tham chiếu tới. Vì obj và obj1 là 2 biến khác nhau nhưng lại đang tham chiếu đến cùng 1 đối tượng, thay đổi này sẽ phản ánh ra bên ngoài phương thức.
Trong phương thức changeValue1, obj được gán một đối tượng mới (new MyObject(10)).Có nghĩa là obj và obj1 là 2 biến khác nhau và tham chiếu đến các đối tượng hoàn toàn khác nhau. Tham chiếu này chỉ tồn tại trong phạm vi của phương thức và không ảnh hưởng đến obj1 bên ngoài phương thức.
Tóm lại, trong Java, mặc dù các tham chiếu đối tượng và kiểu dữ liệu nguyên thủy được truyền vào phương thức theo cơ chế truyền tham trị, việc thao tác trực tiếp lên đối tượng thông qua tham chiếu có thể gây nhầm lẫn về việc thay đổi giá trị bên ngoài phương thức, điều này cần được lập trình viên nắm rõ để tránh các lỗi logic không mong muốn. Qua bài viết này mong rằng các bạn đã hiểu hơn về tham chiếu và tham trị trong java