01/10/2018, 17:18

Về phương thức khởi tạo trong OOP Java: Điều gì sẽ thực sự xảy ra tại bộ nhớ, RAM?

Mình tạo một Blueprint class Cat với các thuộc tính và các phương thức khởi tạo như sau:
indent preformatted text by 4 spacespackage test.java;

public class Cat {
private String name;
private String size;

public String getName() {
	return name;
}

public void setName(String name) {
	this.name = name;
}

public String getSize() {
	return size;
}

public void setSize(String size) {
	this.size = size;
}
//constructor có đối số
public Cat(String name, String size) {
	super();
	this.name = name;
	this.size = size;
}
// constructor không đối sô
public Cat(){
          super();
    }

}

Kế đến trong hàm main mình có thực hiện các dòng code:
indent preformatted text by 4 spaces

public static void main(String[] args) {
	// TODO Auto-generated method stub
	Cat cat;
	Cat myCat = null;
	Cat herCat = new Cat("Kitty", "Big");
	Cat hisCat = new Cat();

	myCat.setName("Java");
	myCat.setSize("SuperBig");

}

}

Điều gì xảy ra tại các ô nhớ khi các câu lệnh này được thực thi vậy? Mn xem giúp mình mình tư duy như này đúng chưa ạ?
Cat cat; -> tạo một biến đối tượng kiểu Cat và tham chỉ tay tới ô nhớ null
Cat myCat = null; -> tương tự
Cat herCat =new Cat("Kitty","Big");-> Tạo đối tượng có “Kitty” “Big” ở 1 vùng nhớ sau đó tạo biến đối tượng herCat chỉ tới đối tượng này
Cat hisCat = new Cat();-> tạo đối tượng trống cũng ở 1 vùng nhớ sau đó tạo biến đối tượng hisCat trỏ tới ô nhớ này
myCat.setName("Java");
myCat.setSize("SuperBig");
-> biến đối tượng myCat có 2 thuộc tính name và size vẫn đang trỏ tới ô nhớ nó trỏ lúc được khởi tạo. Sau đó nhét ‘Java’ vào ô name, nhét “Super Big” vào ô nhớ size

Như vậy có hợp lý không ạ? xin mn cho ý kiến

Trần Hoàn viết 19:32 ngày 01/10/2018

Mình cũng là người làm việc với java một thời gian, không rõ kỹ thuật như thế nào nhưng hiểu như bạn cũng khá là ok.

Theo mentor của mình thì Java nó khác một chút. Mỗi class trong Java đều có một constructor ngầm định (cái này mình không chỉnh được). Tại compile time mỗi class đều được generate ra một object mẫu (file .class).
Các constructor do người dùng viết thực hiện việc sao chép đối tượng mẫu vào một vùng nhớ được cấp phát và tương tác với bản sao này, sau khi constructor này chạy xong thì mới đến phép gán.

Khi bạn gọi Cat cat; thì cat chưa được trỏ đến null, có thể nó giống như C++, con trỏ trỏ đến một ô nhớ rác nào đó, mình không chắc chắn. Biến cat lúc này được đánh dấu là uninitialized, các IDE sẽ ngăn cản không cho bạn tương tác với cat.
image

Ngoài ra việc setNamesetSize không rõ bạn làm như thế nào, nhưng vì String là Class, “Java” là object, nên name trỏ vào “Java”. Nếu như object pool đã tồn tại “Java” thì là name trỏ vào “Java”, còn nếu chưa có thì nhét “Java” vào pool và name trỏ vào “Java”. Chú ý String là một class đặc biệt nên nó hơi dị. Tuy nhiên thông thường, kể cả đối với các class “bình thường” không phải String, các hàm set sẽ làm biến trỏ đến đối tượng mới chứ không phải đem đối tượng đến nơi nó trỏ vào.

Giả sử, hàm setNormalObject được viết như sau:

void setNormalObject(normalObject)
{
	this.normalObject = normalObject;
}

Nếu bạn gọi phương thức đó ở biến a:

a.setNormalObject(b.normalObject);

Khi đó a.normalObject và b.normalObject cùng trỏ tới 1 đối tượng. Giả sử ta thao tác với đối tượng đó:

a.nornalObject.name = "Trần Hoàn";

Kết quả thu được:

System.out.println(b.normalObject.name);//Trần Hoàn
June 14th viết 19:24 ngày 01/10/2018

myCat.setName("Java");
myCat.setSize("SuperBig");
-> biến đối tượng myCat có 2 thuộc tính name và size vẫn đang trỏ tới ô nhớ nó trỏ lúc được khởi tạo. Sau đó nhét ‘Java’ vào ô name, nhét “Super Big” vào ô nhớ size

Cái này là bạn đang ví dụ hay code này chạy thật. myCat đang trỏ tới null, ko có một instance nào của myCat sao gọi setName() hay setSize() dc.

Trần Hoàn viết 19:20 ngày 01/10/2018

Đó lỗi runtime, Null pointer exception. Còn chương trình vẫn sẽ thực thi vì bản chất nó không có lỗi. Bạn đó ví dụ thế thôi.

Bài liên quan
0