Vòng đời của đối tượng trong JAVA

1. Tìm hiểu về một vòng đời của đối tượng

Trước khi nói về chuyện gì xảy ra khi ta tạo một đối tượng, ta cần nói về hai vùng bộ nhớ StackHeap và cái gì được lưu trữ ở đâu.

Đối với Java, HeapStack là hai vùng bộ nhớ mà lập trình viên cần quan tâm, trong đó:

  • Heap là nơi ở của các đối tượng

  • Còn Stack là chỗ của các phương thức và biến địa phương.

Máy ảo Java toàn quyền quản lý hai vùng bộ nhớ này. Lập trình viên không thể và không cần can thiệp.

Đầu tiên, ta hãy phân biệt rõ ràng biến thực thể và biến địa phương, chúng là cái gì và sống ở đâu trong StackHeap.

Nắm vững kiến thức này, ta sẽ dễ dàng hiểu rõ những vấn đề như phạm vi của biến, việc tạo đối tượng, quản lý bộ nhớ, luồng, xử lý ngoại lệ… những điều căn bản mà một lập trình viên Java cần nắm được.

Biến thực thể được khai báo bên trong một lớp chứ không phải bên trong một phương thức. Chúng đại diện cho các trường dữ liệu của mỗi đối tượng (ta có thể điền các dữ liệu khác nhau cho các thực thể khác nhau của lớp đó). Các biến thực thể “sống” bên trong đối tượng chủ của chúng.

toàn quyền quản lý hai vùng bộ nhớ này. Lập trình viên không thể và không cần can thiệp.Đầu tiên, ta hãy phân biệt rõ ràng biến thực thể và biến địa phương, chúng là cái gì và sống ở đâu trongvàNắm vững kiến thức này, ta sẽ dễ dàng hiểu rõ những vấn đề như phạm vi của biến, việc tạo đối tượng, quản lý bộ nhớ, luồng, xử lý ngoại lệ… những điều căn bản mà một lập trình viên Java cần nắm được.được khai báo bên trong một lớp chứ không phải bên trong một phương thức. Chúng đại diện cho các trường dữ liệu của mỗi đối tượng (ta có thể điền các dữ liệu khác nhau cho các thực thể khác nhau của lớp đó). Các biến thực thể “sống” bên trong đối tượng chủ của chúng.

public

 

class

 

ConBo

() {

    

double

 

canNang

;

}
 

Biến địa phương, trong đó có các tham số, được khai báo bên trong một phương thức. Chúng là các biến tạm thời, chúng “sống” bên trong khung bộ nhớ của phương thức và chỉ tồn tại khi phương thức còn nằm trong bộ nhớ Stack, nghĩa là khi phương thức đang chạy và chưa chạy đến ngoặc kết thúc ( } ).

public

 

void

 

ahihi

(

int

 

x

) {

    

int

 

y

 = 

x

++;

}
 

Vậy còn các biến địa phương là các đối tượng?

Nhớ lại rằng trong Java một biến thuộc kiểu không cơ bản thực ra là một tham chiếu tới một đối tượng chứ không phải chính đối tượng đó.

Do đó, biến địa phương đó vẫn nằm trong Stack, còn đối tượng mà nó chiếu tới vẫn nằm trong Heap. Bất kể tham chiếu được khai báo ở đâu, là biến địa phương của một phương thức hay là biến thực thể của một lớp, đối tượng mà nó chiếu tới bao giờ cũng nằm trong heap.

public

 

void

 

ahihi

(

int

 

x

) {

    

int

 

y

 = 

x

++;

    

ConBo

 

conBo

 = 

new

 

ConBo

();

}
 

Vậy biến thực thể nằm ở đâu?

Các biến thực thể đi kèm theo từng đối tượng, chúng sống bên trong vùng bộ nhớ của đối tượng chủ tại heap. Mỗi khi ta gọi new ConBo(), Java cấp phát bộ nhớ cho đối tượng ConBo đó tại heap, lượng bộ nhớ được cấp phát đủ chỗ để lưu giá trị của tất cả các biến thực thể của đối tượng đó.

Nếu biến thực thể thuộc kiểu cơ bản, vùng bộ nhớ được cấp phát cho nó có kích thước tùy theo kích thước của kiểu dữ liệu nó được khai báo. Ví dụ một biến int cần 32 bit.

Còn nếu biến thực thể là đối tượng thì sao?

Chẳng hạn, TestConBo HAS-A ConBo (TestConBo có một ConBo), nghĩa là mỗi đối tượng TestConBo có một biến thực thể là tham chiếu kiểu ConBo.

Java cấp phát bộ nhớ bên trong đối tượng TestConBo đủ để lưu biến tham chiếu conBo. Còn bản thân biến này sẽ chiếu tới một đối tượng ConBo nằm bên ngoài, chứ không phải bên trong, đối tượng TestConBo.

ConBo

 

conBo

 = 

new

 

ConBo

();

TestConBo

 

test

 = 

new

 

TestConBo

();
 

Vậy khi nào đối tượng ConBo được cấp phát bộ nhớ trong heap?

Khi nào lệnh new ConBo() cho nó được chạy – đối tượng ConBo được tạo mới để khởi tạo giá trị cho biến thực thể conBo, lệnh khởi tạo nằm ngay trong khai báo lớp TestConBo.

Cuộc đời của một đối tượng hoàn toàn phụ thuộc vào sự tồn tại của các tham chiếu chiếu tới nó. Nếu vẫn còn một tham chiếu, thì đối tượng vẫn còn sống trong Heap. Nếu không còn một tham chiếu nào chiếu tới nó, đối tượng sẽ chết, hoặc ít ra cũng coi như chết.

Tại sao khi không còn một biến tham chiếu nào chiếu tới thì đối tượng sẽ chết?

Câu trả lời rất đơn giản: Không có tham chiếu, ta không thể với tới đối tượng đó, không thể lấy dữ liệu của nó, không thể yêu cầu nó làm gì. Nói cách khác, nó trở thành một khối bit vô dụng, sự tồn tại của nó không còn có ý nghĩa gì nữa. Garbage collector sẽ phát hiện ra những đối tượng ở tình trạng này và thu dọn vùng bộ nhớ của chúng để tái sử dụng.

Như vậy, để có thể xác định độ dài cuộc đời hữu dụng của đối tượng, ta cần biết được độ dài cuộc đời của các biến tham chiếu. Cái này còn tùy biến đó là biến địa phương hay biến thực thể.

Một biến địa phương chỉ tồn tại bên trong phương thức nơi nó được khai báo, và chỉ sống từ khi phương thức đó được chạy cho đến khi phương thức đó kết thúc.

Một biến thực thể thuộc về một đối tượng và sống cùng với đối tượng đó. Nếu đối tượng vẫn còn sống thì biến thực thể của nó cũng vậy.

Có ba cách hủy tham chiếu tới một đối tượng:

  • Cách #1: Tham chiếu vĩnh viễn ra ngoài phạm vi tồn tại.

public

 

void

 

ahihi

() {

    

ConBo

 

conBo

 = 

new

 

ConBo

();

}
 

Trong trường hợp này, biến conBo sẽ bị huỷ khi ahihi kết thúc.

  • Tham chiếu được chiếu tới một đối tượng khác

public

 

void

 

ahihi

() {

    

ConBo

 

conBo

 = 

new

 

ConBo

();

    

conBo

 = 

new

 

ConBo

();

}
 

Trong trường hợp này, biến conBo chiếu tới đối tượng thứ 2, bỏ rơi đối tượng thứ nhất.

  • Tham chiếu được gán giá trị null

public

 

void

 

ahihi

() {

    

ConBo

 

conBo

 = 

new

 

ConBo

();

    

conBo

 = 

null

;

}
 

Trong trường hợp này, biến conBo bị gán bằng null, ta mất dấu đối tượng và xem như đối tượng bị huỷ.