1. Biến tham chiếu

Trong ngôn ngữ Java, có hai loại biến: biến nguyên thủy và mọi thứ khác. Khi nó xảy ra, bây giờ chúng ta sẽ nói về "mọi thứ khác".

Trên thực tế, sẽ đúng hơn nếu nói rằng có các biến nguyên thủybiến tham chiếu . Vậy những biến tham chiếu này là gì?

Không giống như các kiểu nguyên thủy, có các biến lưu trữ giá trị trực tiếp, các biến tham chiếu lưu trữ các tham chiếu đến các đối tượng. Nghĩa là, có một đối tượng ở đâu đó trong bộ nhớ và biến tham chiếu chỉ lưu địa chỉ của đối tượng này trong bộ nhớ (một tham chiếu đến đối tượng).

Chỉ các kiểu nguyên thủy mới lưu trữ giá trị trực tiếp bên trong các biến. Tất cả các loại khác chỉ lưu trữ một tham chiếu đối tượng . Nhân tiện, bạn đã gặp hai loại biến như vậy — Stringbiến số và biến mảng .

Cả mảng và chuỗi đều là các đối tượng được lưu trữ ở đâu đó trong bộ nhớ. Stringbiến và biến mảng chỉ lưu trữ các tham chiếu đến các đối tượng.

Biến tham chiếu trong Java

int a, int b and double dlà các biến nguyên thủy lưu trữ các giá trị của chúng bên trong chính chúng.

Một String strbiến là một tham chiếu và lưu địa chỉ (tham chiếu) của một Stringđối tượng trong bộ nhớ.

Khi gán một giá trị nguyên thủy cho một biến kiểu nguyên thủy, giá trị của nó được sao chép (nhân bản). Khi gán một biến tham chiếu, chỉ địa chỉ của đối tượng được sao chépbản thân đối tượng không được sao chép .


2. Tài liệu tham khảo là gì?

Sự khác biệt cơ bản giữa các biến tham chiếu và biến nguyên thủy là gì?

Một biến nguyên thủy giống như một cái hộp: bạn có thể lưu trữ một số giá trị trong đó. Một biến tham chiếu giống như một mảnh giấy có số điện thoại trên đó.

Một chiếc ô tô so với chìa khóa ô tô

Hãy tưởng tượng bạn quyết định tặng bạn mình một chiếc ô tô nhân ngày sinh nhật của anh ấy. Bạn sẽ không bọc nó trong hộp và mang theo bên mình: chiếc xe quá lớn cho việc đó.

Sẽ thuận tiện hơn nhiều nếu chỉ đưa chìa khóa ô tô vào một chiếc hộp đủ lớn để chứa chúng. Bạn của bạn sẽ hiểu mọi thứ khi anh ấy lấy chìa khóa ra khỏi hộp. Không cần phải mang theo toàn bộ chiếc xe khi bạn chỉ cần giao chìa khóa.

Một người vs số điện thoại của cô ấy

Hoặc đây là một phép so sánh khác: một người và số điện thoại của cô ấy. Số điện thoại không phải là người, nhưng số điện thoại có thể được sử dụng để gọi cho cô ấy, hỏi cô ấy một số thông tin hoặc cung cấp hướng dẫn.

Tương tự, một tham chiếu được sử dụng để tương tác với một đối tượng. Tất cả các đối tượng tương tác với nhau bằng cách sử dụng các tham chiếu. Thay vì "trao đổi người", chúng tôi chỉ trao đổi số điện thoại.

Khi gán một giá trị cho một biến nguyên thủy, giá trị của nó được sao chép (nhân bản). Khi gán một giá trị cho một biến tham chiếu, chỉ địa chỉ (số điện thoại) của đối tượng được sao chép — bản thân đối tượng không được sao chép.

Một tham chiếu cung cấp một lợi thế nữa: bạn có thể chuyển một tham chiếu đối tượng tới một phương thức nào đó và phương thức đó sẽ có thể sửa đổi (thay đổi) đối tượng bằng cách sử dụng tham chiếu tới nó, gọi các phương thức của nó và truy cập dữ liệu bên trong đối tượng.


3. Chỉ định tài liệu tham khảo

Khi gán biến tham chiếu, chỉ địa chỉ của đối tượng trong bộ nhớ được gán. Bản thân các đối tượng không xuất hiện hoặc biến mất.

Cách tiếp cận này tránh sao chép một lượng lớn bộ nhớ. Nếu bạn cần truyền một đối tượng rất lớn cho một phương thức, chúng ta chỉ cần truyền tham chiếu đối tượng và thế là xong. Tài liệu tham khảo chiếm ít không gian hơn nhiều.

Chỉ định tài liệu tham khảo

Kích thước của tất cả các biến tham chiếu (bất kể loại của chúng) là như nhau — 4 byte (giống như một số nguyên). Nhưng! Nếu ứng dụng của bạn đang chạy trên máy Java 64 bit, thì tất cả các tham chiếu sẽ có kích thước 8 byte (64 bit).

Hơn nữa, các tham chiếu chỉ có thể được gán cho nhau. Bạn không thể thay đổi tham chiếu hoặc gán giá trị tùy ý cho biến tham chiếu:

Mã số Sự miêu tả
String hello = "Hello";
String s = hello;
Điều này được cho phép
String hello = "Hello";
hello++;
Nhưng điều này không được phép
String hello = 0x1234;
Và điều này không được phép

4. Một nulltài liệu tham khảo

Và một biến tham chiếu lưu trữ cái gì nếu chưa có gì được gán cho nó?

Nó lưu trữ một tham chiếu null . nulllà một từ khóa Java đặc biệt có nghĩa là không có tham chiếu (an empty reference). Giá nulltrị có thể được gán cho bất kỳ biến tham chiếu nào.

Tất cả các biến tham chiếu nulltrừ khi chúng được gán một số loại tham chiếu.

Ví dụ:

Mã số Sự miêu tả
class Person
{
   public static String name;
   public static int age;
}


Biến String namecó giá trị mặc định: null.
Biến int agecó giá trị mặc định: 0.

Các biến cục bộ chưa được gán giá trị được coi là chưa được khởi tạo cho cả kiểu nguyên thủy và kiểu tham chiếu.

Nếu một biến lưu trữ một tham chiếu đến một số đối tượng và bạn muốn xóa giá trị của biến đó, thì chỉ cần gán cho nó một tham chiếu null.

Mã số Sự miêu tả
String s = null;
s = "Hello";
s = null;
scửa hàng null.
slưu trữ một tham chiếu đến một đối tượng chuỗi lưu
strữ null.

5. Truyền tham chiếu đến các phương thức

Nếu một phương thức có các tham số là kiểu tham chiếu , thì các giá trị được truyền cho phương thức giống như khi làm việc với các biến không tham chiếu. Tham số chỉ đơn giản được gán giá trị của biến khác.

Ví dụ:

Mã số Sự miêu tả
class Solution
{
   public static void fill(String[] array, String value)
   {
      for (int i = 0; i < array.length; i++)
        array[i] = value;
   }

   public static void main(String[] args)
   {
     String[] data = new String[10];
     fill(data, "Hello");
   }
}


Điền fillvào mảng đã truyền ( array) với giá trị đã truyền ( value).

Khi fillphương thức được gọi, arraytham số được gán một tham chiếu đến datamảng. Biến valueđược gán một tham chiếu đến đối tượng chuỗi ("Xin chào").

Đây là giao diện của bộ nhớ trước khi gọi fill phương thức:

Truyền tham chiếu đến các phương thức

Đây là giao diện của bộ nhớ khi fill phương thức đang chạy :

Truyền tham chiếu đến phương thức 2

Các biến dataarraytham chiếu đến (lưu trữ các tham chiếu đến) cùng một vùng chứa trong bộ nhớ.

Biến valuelưu trữ một tham chiếu đến đối tượng chuỗi ( "Hello").

Các ô của mảng cũng chỉ lưu trữ các tham chiếu đến "Hello"đối tượng.

Trên thực tế, không có đối tượng nào được sao chép — chỉ các tham chiếu được sao chép.



6. So sánh với ngôn ngữ C/C++

Trong các cuộc phỏng vấn, đôi khi các lập trình viên Java được hỏi làm thế nào dữ liệu được chuyển đến các phương thức trong Java? Và đôi khi câu hỏi đặt ra là dữ liệu được truyền theo tham chiếu hay theo giá trị?

Câu hỏi này xuất phát từ C++, nhưng không có ý nghĩa lắm trong Java . Trong Java, các tham số luôn được gán đơn giản các giá trị của các đối số. Vì vậy, câu trả lời đúng sẽ là " theo giá trị ".

Nhưng hãy chuẩn bị để giải thích vị trí của bạn , vì bạn có thể ngay lập tức nghe thấy câu trả lời: "các loại nguyên thủy được truyền theo giá trị và các loại tham chiếu được truyền theo tham chiếu."

Nguồn gốc của vấn đề này bắt nguồn từ thực tế là nhiều lập trình viên Java đã từng là lập trình viên C++ trong quá khứ. Trong ngôn ngữ lập trình đó, câu hỏi về cách truyền tham số cho phương thức là rất quan trọng.

Trong Java, mọi thứ đều rõ ràng: các kiểu nguyên thủy lưu trữ các giá trị và các kiểu tham chiếu cũng lưu trữ một giá trị - một tham chiếu. Đó là câu hỏi liệu một biến có được coi là một giá trị hay không .

Trong C++, một biến có thể lưu trữ cả tham chiếu đến một đối tượng và chính đối tượng đó. Điều này cũng đúng với các kiểu nguyên thủy: một biến nguyên thủy có thể lưu trữ một giá trị hoặc khai báo biến như một tham chiếu đến một tệp int. Vì vậy, để tránh nhầm lẫn, các lập trình viên C++ luôn coi đối tượng là tham chiếu dưới dạng tham chiếu và bản thân đối tượng — dưới dạng giá trị.

Trong C++, bạn có thể dễ dàng gặp tình huống trong đó một biến chứa đối tượng nhưng biến kia lại chứa tham chiếu đến đối tượng đó. Theo đó, câu hỏi biến lưu trữ cái gì — chính đối tượng hay chỉ là một tham chiếu đến nó — là rất quan trọng. Khi một đối tượng được truyền cho một phương thức, nó sẽ được sao chép (nếu được truyền theo giá trị) và không được sao chép (nếu được truyền theo tham chiếu).

Trong Java, tính hai mặt này không tồn tại, vì vậy câu trả lời đúng là: các đối số được truyền cho các phương thức Java theo giá trị . Chỉ là khi chúng ta nói về các biến tham chiếu, giá trị này là một tham chiếu.