Tất cả các developer biết về ngôn ngữ Java đều hiểu cách để khởi tạo một object từ một class, công việc này rất đơn giản nhờ sử dụng từ khóa new
:
1 |
new MyNumber() |
Tùy vào method signature của class được sử dụng để tạo object chúng ta sẽ cần truyền vào một số lượng đối số (argument) nhất định. Ví dụ với class MyNumber
được định nghĩa như sau:
1 2 3 4 5 6 7 |
public MyNumber { public int counter; public MyNumber(init initialValue) { counter = initialValue; } } |
Thì chúng ta có thể khởi tạo object từ class này với đối số truyền vào như sau:
1 |
MyNumber myNumber = new MyNumber(100); |
Tuy nhiên bạn có biết điều gì thực sự diễn ra khi chạy đoạn code trên?
3 Sự Kiện Diễn Ra Khi Khởi Tạo Object
Có 3 sự kiện diễn ra khi chúng ta tạo một object từ class:
- Java (cụ thể là Java Virtual Machine) sẽ lấy ra một địa chỉ bộ nhớ còn trống trong memory để lưu trữ dữ liệu của object. Các biến trong đối tượng mới tạo ra này (gọi là instance variable hay field) được gán cho các giá trị mặc định nếu như chúng được khai báo mà chưa được gán giá trị.
- Tiếp theo Java sẽ gọi phương thức dựng (gọi là constructor method) với các đối số được sử dụng khi khởi tạo object. Ngoài ra các bước
- Cuối cùng Java sẽ trả về địa chỉ bộ nhớ trên RAM. Nếu như một biến được gán giá trị từ việc khởi tạo object thì Java sẽ gán giá trị của bộ nhớ này cho giá trị của biến đó.
Tuy nhiên sẽ được lợi gì nếu như tôi hiểu về quy trình tạo object trên? Để trả lời câu hỏi trên chúng ta sẽ tham khảo một ví dụ sau:
1 2 3 |
MyNumber myNumber = new MyNumber(100); MyNumber newNumber = myNumber; newNumber.counter = 101; |
Lúc này bạn đoán giá trị của myNewNumber.counter
sẽ là bao nhiêu:
1 |
System.out.println(myNumber.counter); |
Câu trả lời là 101
thay vì 100
. Tại sao vậy?
Object Referrence
Nhớ lại 3 sự kiện diễn ra khi khởi tạo object đề cập trong phần trước bạn sẽ thấy lúc này giá trị của biến myNumber
chính là giá trị của địa chỉ bộ nhớ của object khởi tạo. Do đó khi chúng ta gán giá trị của biến newNumber
bằng với biến myNumber
như sau:
1 |
MyNumber newNumber = myNumber; |
Thì lúc này Java sẽ trỏ giá trị của biến newNumber
về địa chỉ bộ nhớ RAM nơi lưu trữ dữ liệu của object. Hay nói cách khác myNumber
và newNumber
tham chiếu tới một địa chỉ duy nhất trên bộ nhớ.
Do đó khi bạn thay đổi giá trị của biến counter của object newNumber
trong dòng code:
1 |
newNumber.counter = 101; |
1 |
newNumber.counter = 101; |
Thì lúc này dữ liệu thực tế bị thay đổi là dữ liệu nằm ở địa chỉ bộ nhớ lưu trữ dữ liệu của object (được sử dụng bởi cả myNumber
và newNumber
).
Tính năng trên trong Java được gọi là tham chiếu tới đối tượng hay object refference. Ở đây chúng ta nói biến newNumber
giữ vai trò là một pointer tham chiếu tới địa chỉ trên RAM lưu trữ dữ liệu của object được khởi tạo trước đó (và gán cho giá trị của biến myNumber
).
Bạn có thể tưởng tượng object giống như một màn hình hiển thị nội dung của một chương trình từ một kênh nào đó như HTV1. Các biến myNumber
và newNumber
giống như các remote điều khiển.
Bạn có thể sử dụng một trong hai remote điều khiển này để chuyển kênh và khi điều đó diễn ra thì màn hình sẽ chuyển sang kênh được thay đổi bởi một trong hai remote.
Derfeference
Điều gì diễn ra khi thay đổi giá trị của newNumber
về một số integer, string hoặc object khác… ví dụ như sau:
1 |
int newNumber = 2017; |
Liệu lúc này myNumber
sẽ nhận giá trị là 2017 hay không?
Câu trả lời là không. Điều này là bởi vì khi bạn gán giá trị khác cho newNumber
thì Java sẽ trỏ giá trị của biến này về một địa chỉ khác trên RAM trên đó lưu trữ dữ liệu mới của nó. Do đó biến myNumber
không bị ảnh hưởng. Tính năng này còn được gọi là object derefference.
Giống như ví dụ ở trên điều gì xảy ra nếu như bạn làm rơi một chiếc remote và nó bị hư? Chiếc remote thứ hai vẫn không bị ảnh hưởng và nó vẫn có thể chuyển kênh.
Nói cách khác nếu bạn thay đổi giá trị của object tại địa chỉ ban đầu thì sự thay đổi này sẽ ảnh hưởng tới tất cả các biến trỏ tới object này (ở ví dụ của chúng ta là hai biến newNumber
và myNumber
).
Cám ơn các bạn đã đọc bài viết này! Hy vọng sẽ giúp ích cho các bạn.