Phần này chúng ta sẽ làm rõ ba vấn đề sau: truyền tham trị là gì(pass by value), truyền tham chiếu(pass by reference) là gì, trong java sử dụng kiểu nào ?
Mục Lục
1 – Truyền tham trị (Pass by value)
Truyền tham trị là việc ta clone ra một bản sao (tạo ra một giá trị mới bằng cách copy giá trị gốc) và thao tác với giá trị của bản sao đó và không làm thay đổi giá trị của bản gốc. Hiểu đơn giản là khi truyền dữ liệu vào hàm và tương tác thì dữ liệu chỉ thay đổi trong hàm đó, mà không làm thay đổi giá trị gốc ban đầu ngoài hàm.
package com.cafeincode.java;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Example {
public static void main(String[] args) {
int counter = 7;
log.info("Before increase:{}", counter);
increaseValue(counter);
log.info("After increase:{}", counter);
}
private static void increaseValue(int counter) {
counter += 1;
log.info("Increase counter:{}", counter);
}
}
chương trình thực hiện như sau:
- Tại dòng 7 trong hàm main(), ta khởi tạo biến counter có giá trị là 7, trước khi gọi hàm increaseValue() thì giá trị của nó giữ nguyên là 7
- Tại dòng 9, khi gọi hàm increaseValue() ta truyền biến counter có giá trị là 7 vào hàm, tuy nhiên dữ liệu của biến này đã được clone ra thành một biến mới, tại đây ta thực hiện cộng thêm 1 đơn vị vào biến counter mới, giá trị của biến counter mới lúc này bằng 8 là giá trị cục bộ trong hàm increaseValue().
- Tại dòng 10 trong hàm main(), ta thực hiện ghi ra giá trị biến counter, lúc này biến counter vẫn giữ nguyên giá trị của nó ban đầu do hàm increaseValue() không tác động được vào giá trị của biến gốc mà chỉ tác động vào biến mà nó clone ra.
2 – Truyền tham chiếu (Pass by reference)
Truyền tham chiếu là kiểu khi truyền giá trị vào hàm và thực hiện tương tác, sửa đổi thì dữ liệu ở trong hay ngoài hàm đều thay đổi, tuy nhiên trong java không có truyền tham chiếu, mà chỉ có truyền tham trị.
Một số website hướng dẫn hiện nay đang hướng dẫn theo kiểu : truyền biến nguyên thủy là tham trị, truyền biến đối tượng là tham chiếu, điều này là sai hoàn toàn.
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class CounterObj {
private String value;
}
Ví dụ 1: truyền đối tượng vào hàm, và khởi tạo một instance mới
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Example {
public static void main(String[] args) {
CounterObj counterObj = new CounterObj("JJJJJ");
log.info("Step 1: Address: {} Value: {}", counterObj, counterObj.getValue());
changeValueObj(counterObj);
log.info("Step 3: Address: {} Value: {}", counterObj, counterObj.getValue());
}
private static void changeValueObj(CounterObj counterObj) {
counterObj = new CounterObj("FFFFF");
log.info("Step 2: Address: {} Value: {}", counterObj, counterObj.getValue());
}
}
Luồng thực hiện đoạn code trên như sau:
- Tại dòng 7, ta thực hiện khởi tạo đối tượng CounterObj, một đối tượng được lưu trong bộ nhớ Heap (giả sử nó có địa chỉ là 6996db8, giá trị của nó lúc này là JJJJJ), đồng thời biến counterObj được lưu trong một khối ô nhớ của hàm main() trong Stack.
- Tại dòng 9, hàm changeValueObj() được gọi, lúc này một biến counterObj được lưu trong khối ô nhớ của hàm changeValueObj() của Stack.
- Tại dòng 14, một đối tượng counterObj mới được tạo, được lưu trong Heap (có địa chỉ là 6504e3b2, giá trị là FFFFF), đồng thời biến counterObj được lưu trong khối ô nhớ của hàm changeValueObj() trong Stack.
- Tại dòng 10, ta in ra địa chỉ và giá trị của đối tượng ban đầu, thì thấy nó không bị thay đổi giá trị, giá trị truyền vào hàm không bị tác động.
Ví dụ 2: truyền đối tượng vào hàm, và thay đổi giá trị trong hàm bằng setter
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Example {
public static void main(String[] args) {
CounterObj counterObj = new CounterObj("JJJJJ");
log.info("Step 1: Address: {} Value: {}", counterObj, counterObj.getValue());
changeValueObj(counterObj);
log.info("Step 3: Address: {} Value: {}", counterObj, counterObj.getValue());
}
private static void changeValueObj(CounterObj counterObj) {
counterObj.setValue("FFFFF");
log.info("Step 2: Address: {} Value: {}", counterObj, counterObj.getValue());
}
}
Luồng thực hiện đoạn code trên như sau:
- Tại dòng 7, ta thực hiện khởi tạo đối tượng CounterObj, một đối tượng được lưu trong bộ nhớ Heap (giả sử nó có địa chỉ là 6996db8, giá trị của nó lúc này là JJJJJ), đồng thời biến counterObj được lưu trong một khối ô nhớ của hàm main() trong Stack.
- Tại dòng 9, hàm changeValueObj() được gọi, lúc này một biến counterObj được lưu trong khối ô nhớ của hàm changeValueObj() của Stack.
- Tại dòng 13, ta truyền biến counterObj vào hàm, lúc này biến counterObj được clone ra thành một bản sao (có địa chỉ là 6996db8, giá trị của nó là JJJJJ)
- Tại dòng 14, ta thực hiện thay đổi giá trị của thuộc tính value, lúc này biến counterObj tham chiếu đến đối tượng có địa chỉ 6996db8 trong Heap, nên giá trị của biến counterObj lúc này đã thay đổi ở cả trong hàm và ngoài hàm, tuy nhiên đây vẫn truyền kiểu tham trị, không phải truyền tham chiếu.
3 – Trong java sử dụng truyền tham chiếu hay truyền tham trị?
Từ các lập luận ở trên thì chúng ta rút ra được rằng, trong java chỉ hỗ trợ truyền tham trị, không hỗ trợ truyền tham chiếu, không phải truyền kiểu nguyên thủy là tham trị còn truyền kiểu đối tượng là tham chiếu đâu nhé.
Xem thêm các bài viết liên quan bên dưới:
- Hướng dẫn cài đặt JDK 8 trên windows
- Phân biệt JDK JRE và JVM trong Java
- Bộ nhớ Heap và bộ nhớ Stack trong Java
- Quy ước đặt tên trong Java (Naming convention)
- Từ khóa trong java và chức năng của nó (keywords)
- Kiểu dữ liệu trong java và tác dụng của nó
- Improve Java Performance: thủ thuật tối ưu [Phần 1]
- Build hệ thống Pub Sub dùng Hazelcast và Spring boot
- Build hệ thống Pub-Sub bằng Kafka+Spring boot (phần 3)
- 13 Plugin không thể thiếu khi làm việc với IntellIJ IDEA
- Những plugins Intellij IDEA tốt nhất trong công việc
- Crack Intellij IDEA new versions 2021
- Crack IntellIJ để code như một senior
- Shortcut Intellij hữu ích để làm việc được hiệu quả hơn
- Git stash giúp bạn trở nên chuyên nghiệp như thế nào?
- Git revert với git reset hoạt động như thế nào
- Active Jrebel để code trong IntellIJ IDEA
- Tìm hiểu cơ chế hoạt động của Apache Kafka (phần 1)
- Tìm hiểu cơ chế hoạt động của Apache Kafka (phần 2)
- Elasticsearch là gì mà bá đạo đến vậy? [Phần 1]
- Cùng nhau tìm hiểu Docker
- Lập trình viên lúc rảnh rỗi thì nên làm gì?
- Câu chuyện phỏng vấn online mùa Covid
- Nói sao để được chào đón, làm thế nào để được ghi nhận