Chào mừng các bạn đến với bài học Java thứ 24, vài học về lớp Object. Đây là bài học trong chuỗi bài về lập trình ngôn ngữ Java của Yellow Code Books.
Trước hết mình xin chúc mừng các bạn đã vượt qua nhiều cửa ải khó khăn trong việc tiếp cận ngôn ngữ lập trình Java, và cả OOP nữa. Đến đây, nếu bạn nào chưa từng lập trình Android, mà muốn tìm hiểu cách viết ứng dụng trên hệ điều hành này, thì bạn hãy bắt đầu đọc các bài học bên lập trình Android được rồi nhé. Tuy nhiên, dù thành tích học hành của các bạn rất đáng nể, nhưng chúng ta vẫn còn khá nhiều kiến thức ở phía trước, do đó mình hi vọng các bạn vẫn luôn sẵn sàng lòng tin và sự hứng khởi trong suốt các bài học về Java và cả các bài học về các ngôn ngữ lập trình khác mà Yellow Code Books mang lại.
Bài hôm nay chúng ta tiếp tục nói sâu hơn về OOP, đặc biệt vẫn là xoay quanh về tính Kế thừa. Ôn lại một chút rằng, nếu như ở ngày nào đấy bạn vừa mới tiếp cận vào kế thừa, rồi bạn làm quen tiếp đến sự phủ quyết, hay ghi đè trong kế thừa, thì đến bài hôm nay, bạn sẽ được làm quen với một lớp, có tên gọi là lớp Object, để xem lớp này ảnh hưởng như thế nào đến việc sử dụng các lớp hay các đối tượng mà bạn đã từng làm quen nhé.
Lớp Object Là Gì?
Việc xuất hiện lớp Object ở thời điểm này có thể khiến bạn có chút bối rối. Thế nhưng khi bạn vừa mới tiếp cận Java, ở các dòng code đầu tiên của bạn, lớp này đã xuất hiện rồi đó. Lớp này có cái tên là Object, nó là một lớp được hệ thống tạo ra sẵn, và hệ thống cũng chỉ định nó là lớp cha cao nhất của tất cả các lớp trong Java.
Để hiểu rõ hơn, chúng ta hãy cùng nhau xem lại khai báo lớp HinhTron đẹp đẽ từ những bài trước.
public class HinhTron { }
Bạn thấy rằng HinhTron này không có kế thừa từ bất cứ lớp nào khác, và bạn nghĩ rằng nó là cha cao nhất, nếu như có khai báo các lớp khác extends từ nó? Không đâu nhé, như mình có nói trên đây, trong Java, nếu như bạn không chỉ định lớp cha cho một lớp nào đó, thì hệ thống mặc định cho lớp đó kế thừa từ một lớp, chính là lớp Object. Thế nhưng vì nó là mặc định được các lớp khác kế thừa đến (trừ lớp đã khai báo kế thừa đến một lớp khác rồi, vì bạn đã biết một lớp không thể có nhiều lớp cha mà), nên bạn không nhất thiết phải khai báo cho rõ ràng làm chi sự kế thừa đến lớp Object này.
Code dưới đây mình muốn viết ra cho nó tường minh thôi nhé, cho bạn biết rằng việc khai báo như thế này là ngầm định, chẳng ai viết như vậy đâu.
public class HinhTron extends Object { }
Lớp Object Có Tác Dụng Gì?
Vâng chắc chắn bạn sẽ thắc mắc, thế thì sinh ra cái lớp quái quỷ này làm gì, để mà nó làm cha người khác à?
Thực ra, nếu đọc qua ý của mình sau đây, bạn sẽ thấy rằng lớp Object khá là quan trọng.
Thứ nhất, Object có thể dùng để bạn khai báo trước một đối tượng mà bạn còn chưa biết cái đối tượng đó là đối tượng gì, về sau khi vào từng tình huống cụ thể, bạn sẽ ép kiểu lớp Object tạm này về các lớp con cụ thể tương ứng. Nghe qua có vẻ mơ hồ, nhưng bạn hãy ghi nhớ, bạn sẽ hiểu rõ lợi ích này qua các bài học sau này.
Thứ hai, như bạn đã biết công dụng chính mà sự kế thừa mang lại, đó là công dụng giúp gom nhóm các giá trị giống nhau của các lớp vào cùng một lớp cơ sở, như ví dụ về lớp HinhHoc chính là lớp cơ sở cho các lớp HinhTron, HinhChuNhat, HinhVuong,… ở bài 21. Thì lớp Object cũng vậy, lớp này lúc này đóng vai trò là một lớp cơ sở cho bất kỳ lớp nào bạn tạo ra trong một project Java. Vậy thì lớp cơ sở này đây sẽ chứa các giá trị chung nhất hữu ích nào cho các lớp còn lại vậy, mời bạn xem tiếp.
Các Phương Thức Mà Lớp Object Cung Cấp
Các phương thức dưới đây của lớp Object không mang ý nghĩa thực tiễn tức thì, tức là bạn chỉ đọc qua rồi để đó thôi, sau này có dịp thì dùng đến. Bạn nên nhớ là các phương thức này được Object cung cấp sẵn cho tất cả các lớp, nên hôm nay bạn đọc sơ qua, rồi nhớ lấy, sau này có dịp thì lôi ra dùng chứ đừng tự thiết kế lại làm chi cho mất công nhé.
public final Class getClass()
Phương thức này trả về một lớp Class, lớp Class này chứa đựng các thông tin được xây dựng sẵn liên quan đến đối tượng đang gọi.
Bạn có thể tham khảo code sau, bạn thấy đó, chúng ta đâu có khai báo các phương thức này đâu, nó nằm sẵn ở lớp Object và chúng ta chỉ việc lấy ra dùng mà thôi.
public static void main(String[] args) { HinhTron hinhTron = new HinhTron(); System.out.println("Thông tin đối tượng HinhTron: " + hinhTron.getClass()); System.out.println("Thông tin đối tượng HinhTron: " + hinhTron.getClass().getName()); System.out.println("Thông tin đối tượng HinhTron: " + hinhTron.getClass().getSimpleName()); }
Kết quả in ra vài thông tin hữu ích của đối tượng này, tùy vào phương thức bạn gọi sâu vào trong của Class.
int hashCode()
Phương thức này trả về một giá trị hash code. Mình chưa từng dùng qua phương thức này, nhưng mình nghĩ nó có thể được dùng như các giá trị giúp phân biệt các đối tượng với nhau.
Như code dưới đây, bạn có thể thấy khi in hash code của hai đối tượng của cùng một lớp.
public static void main(String[] args) { HinhTron hinhTron1 = new HinhTron(); HinhTron hinhTron2 = new HinhTron(); System.out.println("Hashcode của HinhTron 1: " + hinhTron1.hashCode()); System.out.println("Hashcode của HinhTron 2: " + hinhTron2.hashCode()); }
boolean equals(Object obj)
Phương thức equals() này có quen không bạn? Không à? Nhớ lại đi. 🙂
Thực ra thì ở bài 13, bài học về Chuỗi, mình có nói đến phương thức equals() này ở Chuỗi giúp so sánh hai Chuỗi có giống nhau không. Giờ thì bạn đã biết rằng Chuỗi cũng là một Đối tượng, và vì vậy nó cũng sẽ kế thừa phương thức equals() này từ lớp cha Object. Nhưng thú vị hơn, đó là equals() của Chuỗi đã có override lại phương thức này của lớp cha chứ không hoàn toàn kế thừa nhé.
Vậy cũng tương tự như Chuỗi, phương thức equals() này giúp so sánh hai đối tượng bất kỳ với nhau xem chúng có giống nhau không. Hai đối tượng được gọi là giống nhau, không phải là do chúng được tạo ra từ một lớp, mà vì chúng có giá trị tham chiếu như nhau. Vấn đề về tham chiếu này thực chất có liên quan đến kiến thức về con trỏ, nhưng Java không muốn các lập trình viên của mình biết về con trỏ, vậy thì mình sẽ nói đến cái khái niệm tham chiếu sau nhé, lằng nhằng lắm.
Chắc bạn cũng đoán được kết quả trả về của hai cách so sánh dưới đây rồi đúng không nào.
public static void main(String[] args) { HinhTron hinhTron1 = new HinhTron(); HinhTron hinhTron2 = new HinhTron(); System.out.println(hinhTron1.equals(hinhTron2)); }
public static void main(String[] args) { HinhTron hinhTron1 = new HinhTron(); HinhTron hinhTron2 = hinhTron1; System.out.println(hinhTron1.equals(hinhTron2)); }
Bạn cũng có thể in ra hash code giữa chúng để có thể thấy mối liên hệ giữa equals() và hashCode() nhé.
Object clone()
Phương thức này giúp khởi tạo và trả về một bản sao của đối tượng được gọi. Thực chất phương thức này mình chỉ nêu ra mà không có ví dụ cụ thể cho nó, vì hiện tại lớp Object đang khai báo Khả năng truy cập của phương thức này là protected. Bạn sẽ hiểu loại khả năng truy cập này sau, nhưng đại loại là nó được bảo vệ và chỉ hữu dụng khi lớp con của nó override phương thức này thôi.
String toString()
Phương thức này giúp trả về một kiểu Chuỗi diễn đạt cho đối tượng này. Nội dung của nó là sự kết hợp của chuỗi (getClass().getName() + “@” + Integer.toHexString(hashCode())).
Có một điều thú vị rằng là, phương thức này có thể không cần phải gọi đến một cách tường minh. Chính vì vậy mà các đối tượng Chuỗi mà bạn đã làm quen không cần bất cứ câu lệnh toString() nào, như ví dụ dưới đây cho thấy chương trình in ra hai đối tượng, một Chuỗi, cộng với một hinhTron1.
public static void main(String[] args) { HinhTron hinhTron1 = new HinhTron(); System.out.println("Không cần gọi toString() tường minh: " + hinhTron1); }
Nó tương đương với cách bạn gọi toString() một cách tường minh như sau, nhưng bạn không cần phải làm vậy.
public static void main(String[] args) { HinhTron hinhTron1 = new HinhTron(); System.out.println("Thử gọi toString() tường minh: ".toString() + hinhTron1.toString()); }
Kết quả thực thi của chúng là giống nhau.
void finalize()
Các lớp con của Object có thể overide lại phương thức này, để có thể khai báo vào trong đó các hành động giải phóng các tài nguyên đang dùng, trước khi bộ dọn rác (Garbage Collection – Mình có nhắc đến bộ dọn rác này một chút ở bài mở màn) tiến hành dọn dẹp đối tượng không còn được sử dụng này.
Bạn cũng thấy rằng phương thức này được gọi một cách tự động bởi hệ thống. Và nó cũng khá chuyên sâu nữa, thỉnh thoảng được dùng đến khi bạn đang sử dụng và muốn giải phóng các tài nguyên liên quan đến đọc file, hay kết nối mạng, mà chúng ta sẽ làm quen ở các bài sau.
Ngoài các phương thức hữu ích trên mà lớp Object mang lại cho các lớp con của nó, thì còn có một số phương thức khác nữa, như notify(), notifyAll(), wait() sẽ được mình nhắc đến ở các bài học có liên quan đến chúng sau.
Cảm ơn bạn đã đọc các bài viết của Yellow Code Books. Bạn hãy đánh giá 5 sao nếu thấy thích bài viết, hãy comment bên dưới nếu có thắc mắc, hãy để lại địa chỉ email của bạn để nhận được thông báo mới nhất khi có bài viết mới, và nhớ chia sẻ các bài viết của Yellow Code Books đến nhiều người khác nữa nhé.
Bài Kế Tiếp
Bài hôm sau chúng ta cùng nói về một vấn đề mà mình đã hứa từ rất lâu, vấn đề về Khả năng truy cập vào các giá trị bên trong một lớp.
Bài viết hay, chi tiết, viết tiếp đi admin
Âu cơ 😉
Bao giờ thì xong all về ngôn ngữ Java ad ới :))
Theo cái sườn Java của mình, thì tổng bài viết về Java trong khoảng 40-45 bài. Như vậy còn tầm hơn 10 bài nữa kể từ hôm nay (hiện đã ra đến bài 30 rồi). Các bài cuối này mình sẽ cố gắng viết trong hết tháng 10, rồi sẽ ra pdf toàn bộ cho mọi người có thể đọc offline mà không cần phải lúc nào cũng vào blog của mình, chỉ cần online vào để chém gió mà thôi 😉
e cảm ơn ad ạ :)) các bài viết của ad hay lắm ạ đầy đủ nữa :)) ad cố gắng ạ :))
Cảm ơn bạn 🙂
Ad ơi, làm sao để nhận được file pdf của ad vậy?
Hiện tại mình không còn chia sẻ file PDF nữa rồi bạn, một phần vì file đó cũng cũ rồi, để mình tìm một công cụ khác giúp generate file PDF dễ dàng hơn, khi đó sẽ chia sẻ lại.
Hay lắm nhưng lớp Object này có vẻ trừu tượng hơn cả, ít ứng dụng thực tế ad nhỉ?
cám ơn bạn