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ớ Stack và Heap và cái gì được lưu trữ ở đâu.
Đối với Java, Heap và Stack 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 Stack và Heap.
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ỷ.