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
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.
Ngoài ra việc setName và setSize 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:
Nếu bạn gọi phương thức đó ở biến a:
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 đó:
Kết quả thu được:
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.
Đó 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.