Kế thừa Java định nghĩa mối quan hệ is-a giữa một lớp cha và các lớp con của nó. Điều này có nghĩa là một Đối tượng của lớp con có thể được sử dụng ở bất cứ nơi nào có thể sử dụng đối tượng của lớp cha. Kế thừa lớp trong Java được sử dụng để xây dựng các Lớp mới từ các Lớp hiện có. Quan hệ thừa kế mang tính bắc cầu. nếu Lớp x mở rộng Lớp y, thì Lớp z, mở rộng Lớp x, cũng sẽ kế thừa từ Lớp y
Ví dụ: một Lớp xe hơi có thể kế thừa một số thuộc tính từ một Lớp xe nói chung. Ở đây chúng tôi thấy rằng Lớp cơ sở là Lớp xe và lớp con là Lớp xe cụ thể hơn. Một lớp con phải sử dụng mệnh đề mở rộng để dẫn xuất từ một siêu lớp phải được viết trong tiêu đề của định nghĩa lớp con. Lớp con kế thừa các thành viên của lớp cha và do đó thúc đẩy tái sử dụng mã. Bản thân lớp con có thể thêm hành vi và thuộc tính mới của nó. java. lang thang. Lớp đối tượng luôn đứng đầu bất kỳ hệ thống phân cấp kế thừa Lớp nào
Điều gì là không thể khi sử dụng Kế thừa lớp Java?
Các thành viên riêng của lớp cha không được kế thừa bởi lớp con và chỉ có thể được truy cập gián tiếp
Vì các hàm tạo và khối khởi tạo không phải là thành viên của Lớp nên chúng không được kế thừa bởi lớp con
Một lớp con chỉ có thể mở rộng một lớp cha
Các thành viên có khả năng truy cập mặc định trong lớp cha cũng không được kế thừa bởi các lớp con trong các gói khác, vì các thành viên này chỉ có thể truy cập bằng tên đơn giản của chúng trong các lớp con trong cùng gói với lớp cha
cái này và siêu từ khóa
Hai từ khóa this và super giúp bạn đặt tên rõ ràng cho trường hoặc Phương thức mà bạn muốn. Sử dụng từ khóa này và siêu bạn có toàn quyền kiểm soát việc gọi một Phương thức hoặc trường trong cùng một Lớp hay gọi từ lớp cha trực tiếp. từ khóa này được sử dụng làm tham chiếu đến Đối tượng hiện tại, là một thể hiện của Lớp hiện tại. Từ khóa super cũng tham chiếu đến Đối tượng hiện tại, nhưng là một thể hiện của lớp cha của lớp hiện tại
từ khóa này tham chiếu đến Đối tượng hiện tại và rất hữu ích trong các tình huống khi một biến cục bộ ẩn hoặc che khuất một trường có cùng tên. Nếu một Phương thức cần chuyển Đối tượng hiện tại sang một Phương thức khác, thì nó có thể làm như vậy bằng cách sử dụng tham chiếu này. Lưu ý rằng tham chiếu này không thể được sử dụng trong ngữ cảnh tĩnh, vì mã tĩnh không được thực thi trong ngữ cảnh của bất kỳ Đối tượng nào
Trong số các khái niệm quan trọng nhất trong lập trình hướng đối tượng là các khái niệm về kế thừa và đa hình. Kế thừa lớp là cơ chế theo đó một lớp có được [kế thừa] các phương thức và biến của các lớp cha của nó. Hãy xem xét một ví dụ về hình thức thừa kế tự nhiên. Giống như ngựa kế thừa các thuộc tính và hành vi liên quan đến động vật có vú và động vật có xương sống, một lớp con Java kế thừa các thuộc tính và hành vi của các lớp cha của nó
Như thể hiện trong sơ đồ trên, gốc của hệ thống phân cấp, luôn được hiển thị ở trên cùng, lớp
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
0 chứa các thuộc tính chung nhất, chẳng hạn như còn sống và có thể di chuyển. Tất cả các loài động vật chia sẻ các thuộc tính này. Lớp động vật có xương sống là một loại động vật chuyên biệt hơn một chút, trong đó động vật có xương sống có xương sống. Tương tự, lớp động vật có vú là một chuyên ngành sâu hơn so với động vật có xương sống ở chỗ động vật có vú là loài máu nóng và nuôi con non. Cuối cùng, lớp ngựa là một chuyên ngành sâu hơn so với lớp động vật có vú, trong đó tất cả các con ngựa đều có bốn chân. Một số động vật có vú, chẳng hạn như con người và chim cánh cụt, không có bốn chân. Do đó, nhờ vị trí của lớp trong hệ thống phân cấp này, chúng ta có thể suy ra rằng ngựa là động vật có xương sống bốn chân, di chuyển, sống, có máu nóng và nuôi con non.Chúng tôi đã cố tình sử dụng một ví dụ từ thế giới tự nhiên để chỉ ra rằng khái niệm kế thừa trong Java được lấy cảm hứng từ đối tác của nó trong thế giới tự nhiên. Nhưng chính xác thì khái niệm kế thừa áp dụng cho Java [và cho các ngôn ngữ hướng đối tượng khác] như thế nào?
Sử dụng một phương pháp kế thừa
Trong Java, các phương thức đối tượng công khai và được bảo vệ cũng như các biến đối tượng của một lớp cha được kế thừa bởi tất cả các lớp con của nó. Điều này có nghĩa là các đối tượng thuộc các lớp con có thể sử dụng các biến và phương thức kế thừa như của chính chúng.
Ví dụ: tất cả các lớp Java đều là lớp con của lớp
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
2, đây là lớp tổng quát nhất trong hệ thống phân cấp lớp của Java. Một phương thức public được định nghĩa trong lớp public String toString[] {
return "My name is " + name + " and I am a Student.";
}
2 là phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4. Bởi vì mọi lớp trong hệ thống phân cấp Java đều là lớp con của public String toString[] {
return "My name is " + name + " and I am a Student.";
}
2, nên mọi lớp đều kế thừa phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4. Do đó, public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 có thể được sử dụng với bất kỳ đối tượng Java nàoGiả sử chúng ta định nghĩa một lớp Sinh viên như sau
public class Student {
protected String name;
public Student[String s] {
name = s;
}
public String getName[] {
return name;
}
}
Hình trên cho thấy mối quan hệ giữa lớp này và lớp
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
2. Là một lớp con của Object, lớp public String toString[] {
return "My name is " + name + " and I am a Student.";
}
9 kế thừa phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4. Do đó, đối với một đối tượng Sinh viên nhất định, chúng ta có thể gọi public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 của nó như saupublic String toString[] {
return "My name is " + name + " and I am a Student.";
}
2Cái này hoạt động ra sao?
Lưu ý trong ví dụ này rằng biến stu được khai báo là kiểu
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
9 và được gán một thể hiện của lớp public String toString[] {
return "My name is " + name + " and I am a Student.";
}
9. Khi biểu thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
76 được thực thi, đầu tiên Java sẽ tìm trong lớp public String toString[] {
return "My name is " + name + " and I am a Student.";
}
9 để tìm định nghĩa của phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4. Không tìm thấy cái nào ở đó, nó sẽ tìm kiếm trong hệ thống phân cấp lớp public String toString[] {
return "My name is " + name + " and I am a Student.";
}
9 [Hình. số 8. 2] cho đến khi tìm thấy định nghĩa công khai hoặc được bảo vệ của phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4. Trong trường hợp này, nó tìm thấy một phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 trong lớp Đối tượng và nó thực thi triển khai của public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 đóGhi đè một phương thức kế thừa
Việc triển khai mặc định của
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 trả về tên của lớp đối tượng và địa chỉ [e. g. public String toString[] {
return "My name is " + name + " and I am a Student.";
}
54] nơi đối tượng được lưu trữ trong bộ nhớ. Tuy nhiên, loại kết quả này quá chung chung và không đặc biệt hữu íchPhương thức
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 được thiết kế để ghi đè—nghĩa là được định nghĩa lại trong các lớp con của Đối tượng. Ghi đè public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 trong một lớp con cung cấp một biểu diễn chuỗi tùy chỉnh của các đối tượng trong lớp con đóĐể ghi đè
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 cho lớp public String toString[] {
return "My name is " + name + " and I am a Student.";
}
9, hãy thêm định nghĩa phương thức sau vào lớp public String toString[] {
return "My name is " + name + " and I am a Student.";
}
9public String toString[] {
return "My name is " + name + " and I am a Student.";
}
Với sự thay đổi này, hệ thống phân cấp lớp
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
9 đã sửa đổi được hiển thị trong hình bên dưới. Lưu ý rằng cả Object và public String toString[] {
return "My name is " + name + " and I am a Student.";
}
9 đều chứa các triển khai của public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4. Bây giờ khi biểu thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
76 được gọi, đầu ra sau đây, nhiều thông tin hơn, sẽ được tạopublic String toString[] {
return "My name is " + name + " and I am a Student.";
}
7Trong trường hợp này, khi Java gặp lệnh gọi phương thức
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
76, nó sẽ gọi phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 mà nó tìm thấy trong lớp public String toString[] {
return "My name is " + name + " and I am a Student.";
}
9Liên kết tĩnh và liên kết động
Cơ chế mà Java sử dụng trong các ví dụ này được gọi là liên kết động, trong đó liên kết giữa lệnh gọi phương thức và triển khai phương thức chính xác được thực hiện trong thời gian chạy. Trong liên kết động, một cuộc gọi phương thức được liên kết với việc triển khai đúng phương thức trong thời gian chạy bởi Máy ảo Java [JVM]
Liên kết động tương phản với liên kết tĩnh, cơ chế mà trình biên dịch Java giải quyết mối liên kết giữa lệnh gọi phương thức và triển khai phương thức chính xác khi chương trình được biên dịch. Để liên kết động hoạt động, JVM cần duy trì một số loại biểu diễn của hệ thống phân cấp lớp Java, bao gồm các lớp do lập trình viên định nghĩa. Khi JVM gặp một lệnh gọi phương thức, nó sẽ sử dụng thông tin về hệ thống phân cấp lớp để liên kết lệnh gọi phương thức với việc triển khai đúng phương thức đó
Trong Java, tất cả các lệnh gọi phương thức đều sử dụng liên kết động ngoại trừ các phương thức được khai báo là cuối cùng hoặc riêng tư. Các phương thức cuối cùng không thể bị ghi đè, vì vậy việc khai báo một phương thức là cuối cùng có nghĩa là trình biên dịch Java có thể liên kết nó với cách triển khai chính xác. Tương tự, các phương thức riêng tư không được kế thừa và do đó không thể ghi đè trong một lớp con. Trên thực tế, các phương thức riêng tư là các phương thức cuối cùng và trình biên dịch có thể thực hiện liên kết tại thời điểm biên dịch
đa hình
Cơ chế liên kết động của Java, còn được gọi là liên kết muộn hoặc liên kết thời gian chạy, dẫn đến cái được gọi là tính đa hình. Tính đa hình là một tính năng của các ngôn ngữ hướng đối tượng, theo đó cùng một lệnh gọi phương thức có thể dẫn đến các hành vi khác nhau tùy thuộc vào loại đối tượng mà lệnh gọi phương thức được thực hiện. Thuật ngữ đa hình có nghĩa là, theo nghĩa đen, có nhiều [đa] hình dạng [hình thái]. Đây là một ví dụ đơn giản
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
5Biến
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
17 được khai báo là kiểu public String toString[] {
return "My name is " + name + " and I am a Student.";
}
2. Đây là loại tĩnh hoặc khai báo của nó. Kiểu tĩnh của một biến không bao giờ thay đổi. Tuy nhiên, một biến cũng có kiểu thực hoặc kiểu động. Đây là loại thực tế của đối tượng đã được gán cho biến. Như bạn đã biết, một biến Đối tượng có thể được gán đối tượng từ bất kỳ lớp con Đối tượng nào. Trong câu lệnh thứ hai, public String toString[] {
return "My name is " + name + " and I am a Student.";
}
17 được gán một đối tượng Sinh viên. Do đó, tại thời điểm này trong chương trình, kiểu thực sự của biến public String toString[] {
return "My name is " + name + " and I am a Student.";
}
17 là Sinh viên. Khi public String toString[] {
return "My name is " + name + " and I am a Student.";
}
51 được gọi ở dòng thứ ba, Java bắt đầu tìm kiếm phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 tại lớp Sinh viên, vì đó là kiểu thực của biếnỞ dòng thứ tư, chúng ta gán một đối tượng lớp
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
53 khác cho public String toString[] {
return "My name is " + name + " and I am a Student.";
}
17, do đó thay đổi kiểu thực tế của nó thành public String toString[] {
return "My name is " + name + " and I am a Student.";
}
53. Do đó, khi public String toString[] {
return "My name is " + name + " and I am a Student.";
}
56[] được gọi ở dòng cuối cùng, phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 bị ràng buộc với triển khai được tìm thấy trong lớp public String toString[] {
return "My name is " + name + " and I am a Student.";
}
53Do đó, chúng ta thấy rằng cùng một biểu thức,
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
51, được liên kết luân phiên với hai triển khai public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 khác nhau, dựa trên loại thực tế của đối tượng, public String toString[] {
return "My name is " + name + " and I am a Student.";
}
17, trên đó nó được gọi. Đây là đa hìnhĐiểm quan trọng ở đây là tính đa hình xảy ra khi một phương thức bị ghi đè được gọi trên một biến siêu lớp, e. g. ,
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
17. Trong trường hợp như vậy, việc triển khai phương thức thực tế được gọi được xác định trong thời gian chạy. Việc xác định phụ thuộc vào loại đối tượng được gán cho biến. Do đó, chúng tôi nói rằng cuộc gọi phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
51 là đa hình vì nó được liên kết với các triển khai khác nhau của public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 tùy thuộc vào loại thực tế của đối tượng được liên kết với public String toString[] {
return "My name is " + name + " and I am a Student.";
}
17Đa hình và thiết kế hướng đối tượng
Bây giờ chúng ta đã hiểu cách hoạt động của tính kế thừa và tính đa hình trong Java, sẽ rất hữu ích khi xem xét một ví dụ minh họa cách các cơ chế này có thể hữu ích trong việc thiết kế các lớp và phương thức.
Các phương thức
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
06 và public String toString[] {
return "My name is " + name + " and I am a Student.";
}
07 là ví dụ về các phương thức quá tải, nghĩa là các phương thức có cùng tên nhưng danh sách tham số khác nhau. Hãy nhớ rằng chữ ký của một phương thức liên quan đến tên của nó, cộng với loại, số và thứ tự của các tham số của nó. Các phương thức có cùng tên nhưng khác tham số được gọi là quá tảiDưới đây là chữ ký của một số phương thức print[] và println[] khác nhau
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
1Về cơ bản, có một phương thức
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
08 và public String toString[] {
return "My name is " + name + " and I am a Student.";
}
09 cho mọi loại dữ liệu nguyên thủy, cộng với các phương thức để in bất kỳ loại đối tượng nào. Khi Java gặp một biểu thức liên quan đến public String toString[] {
return "My name is " + name + " and I am a Student.";
}
08 hoặc public String toString[] {
return "My name is " + name + " and I am a Student.";
}
09, nó sẽ chọn phương thức cụ thể để gọi. Để xác định phương thức chính xác, Java dựa vào sự khác biệt trong chữ ký của các phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
08 khác nhau. Ví dụ: vì đối số của nó là một public String toString[] {
return "My name is " + name + " and I am a Student.";
}
83, nên biểu thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
84 được liên kết với phương thức có chữ ký là public String toString[] {
return "My name is " + name + " and I am a Student.";
}
85 vì tham số của nó là một public String toString[] {
return "My name is " + name + " and I am a Student.";
}
83Sử dụng public String toString[] {
return "My name is " + name + " and I am a Student.";
}
1 để tham khảo Superclass
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
Một câu hỏi có thể xảy ra với bạn là. Khi bạn ghi đè phương thức mặc định
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4, thì có thể gọi phương thức mặc định trên đối tượng Sinh viên không? . Ví dụ, giả sử rằng trong lớp Student, bạn muốn nối kết quả của cả phương thức mặc định và phương thức mới public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4. Biểu thức sau đây sẽ thực hiện điều đópublic String toString[] {
return "My name is " + name + " and I am a Student.";
}
5Từ khóa
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
1 chỉ định rằng public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 đầu tiên là từ khóa được triển khai trong siêu lớp. public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 thứ hai đơn giản đề cập đến phiên bản được triển khai trong lớp. Chúng ta sẽ xem thêm các ví dụ về cách sử dụng từ khóa super trong các phần sauKế thừa và Constructor
Cơ chế kế thừa của Java áp dụng cho các biến và phương thức thể hiện công khai và được bảo vệ của một lớp. Nó không áp dụng cho các hàm tạo của một lớp. Để minh họa một số ý nghĩa của tính năng ngôn ngữ này, hãy định nghĩa một lớp con của
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
9 được gọi là public String toString[] {
return "My name is " + name + " and I am a Student.";
}
15public String toString[] {
return "My name is " + name + " and I am a Student.";
}
0Bởi vì
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
15 là một lớp con của public String toString[] {
return "My name is " + name + " and I am a Student.";
}
9, nên nó kế thừa các phương thức và biến thể hiện công khai và được bảo vệ từ public String toString[] {
return "My name is " + name + " and I am a Student.";
}
9. Vì vậy, một public String toString[] {
return "My name is " + name + " and I am a Student.";
}
15 có một biến đối tượng là name và nó có một phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
200 công khai. Nhớ lại rằng một phần tử được bảo vệ, chẳng hạn như biến tên trong lớp public String toString[] {
return "My name is " + name + " and I am a Student.";
}
9, chỉ có thể truy cập được trong lớp và các lớp con của nó. Không giống như các phần tử công khai, nó không thể truy cập được đối với các lớp khácLưu ý cách chúng tôi đã triển khai hàm tạo
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
202. Bởi vì các hàm tạo của lớp cha không được kế thừa, chúng ta phải triển khai hàm tạo này trong lớp con nếu chúng ta muốn có thể gán tên của CollegeStudent trong quá trình xây dựng đối tượng. Cuộc gọi phương thức, public String toString[] {
return "My name is " + name + " and I am a Student.";
}
203, được sử dụng để gọi phương thức khởi tạo của lớp bậc trên và chuyển nó vào ____1204, tên của học sinh. Hàm tạo của lớp bậc trên sau đó sẽ gán public String toString[] {
return "My name is " + name + " and I am a Student.";
}
204 cho biến tênNhư chúng ta đã lưu ý, một lớp con không kế thừa các hàm tạo từ các lớp cha của nó. Tuy nhiên, nếu hàm tạo của lớp con không gọi hàm tạo của lớp bậc trên một cách rõ ràng, thì Java sẽ tự động gọi hàm tạo của lớp bậc trên mặc định—trong trường hợp này là
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
206. Theo hàm tạo siêu lớp mặc định, chúng tôi muốn nói đến hàm tạo không có tham số. Đối với một lớp con nằm dưới một vài lớp trong hệ thống phân cấp, việc gọi hàm tạo public String toString[] {
return "My name is " + name + " and I am a Student.";
}
206 tự động này sẽ được lặp lại lên trên trong toàn bộ hệ thống phân cấp của lớp. Do đó, khi một public String toString[] {
return "My name is " + name + " and I am a Student.";
}
15 được xây dựng, Java sẽ tự động gọi public String toString[] {
return "My name is " + name + " and I am a Student.";
}
209 và public String toString[] {
return "My name is " + name + " and I am a Student.";
}
210. Lưu ý rằng nếu một trong các lớp cha không chứa hàm tạo mặc định, điều này sẽ dẫn đến lỗi cú phápNếu bạn nghĩ về điều này, nó có ý nghĩa. Làm thế nào khác các yếu tố kế thừa của đối tượng sẽ được tạo ra? . Hàm tạo
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
15 sau đó mở rộng định nghĩa của lớp public String toString[] {
return "My name is " + name + " and I am a Student.";
}
9. Tương tự, để một đối tượng public String toString[] {
return "My name is " + name + " and I am a Student.";
}
9 có các thuộc tính chung cho tất cả các đối tượng, một thể hiện public String toString[] {
return "My name is " + name + " and I am a Student.";
}
2 phải được tạo và sau đó mở rộng thành một public String toString[] {
return "My name is " + name + " and I am a Student.";
}
9Do đó, trừ khi một hàm tạo gọi một hàm tạo của lớp bậc trên một cách rõ ràng, Java sẽ tự động gọi các hàm tạo của lớp bậc trên mặc định. Nó thực hiện điều này trước khi thực thi mã trong hàm tạo của chính nó. Ví dụ: nếu bạn có hai lớp,
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
220 và public String toString[] {
return "My name is " + name + " and I am a Student.";
}
221, trong đó public String toString[] {
return "My name is " + name + " and I am a Student.";
}
221 là lớp con của public String toString[] {
return "My name is " + name + " and I am a Student.";
}
220, thì bất cứ khi nào bạn tạo một thể hiện của public String toString[] {
return "My name is " + name + " and I am a Student.";
}
221, trước tiên, Java sẽ gọi hàm tạo của public String toString[] {
return "My name is " + name + " and I am a Student.";
}
220 trước khi thực thi mã trong hàm tạo của public String toString[] {
return "My name is " + name + " and I am a Student.";
}
221 để lớp cơ sở được khởi tạo. Do đó, hành vi mặc định của Java trong quá trình xây dựng public String toString[] {
return "My name is " + name + " and I am a Student.";
}
221 tương đương với việc triển khai hàm tạo của public String toString[] {
return "My name is " + name + " and I am a Student.";
}
221 sau đâypublic String toString[] {
return "My name is " + name + " and I am a Student.";
}
8Ví dụ,
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
1Nó sẽ in
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
20Các lớp trừu tượng, giao diện và đa hình
Trong Java, có ba loại đa hình
- Ghi đè một phương thức kế thừa
- Thực hiện một phương pháp trừu tượng
- Triển khai giao diện Java
Trong phần trước chúng ta đã thấy các ví dụ về loại đa hình đầu tiên. Tất cả các dạng đa hình đều dựa trên cơ chế liên kết động của Java. Trong phần này, chúng tôi sẽ phát triển một ví dụ minh họa hai loại đa hình khác và thảo luận về một số hàm ý thiết kế liên quan đến việc chọn một hoặc một cách tiếp cận khác
Triển khai một phương thức trừu tượng
Một tính năng quan trọng của tính đa hình là khả năng gọi một phương thức đa hình đã được định nghĩa một cách trừu tượng trong lớp cha. Để minh họa tính năng này, chúng tôi sẽ phát triển một hệ thống phân cấp các động vật mô phỏng tạo ra âm thanh đặc trưng của động vật, một ví dụ được sử dụng rộng rãi để minh họa tính đa hình
Như chúng ta đã biết từ thời thơ ấu, động vật có những cách nói đặc biệt. Con bò kêu “moo”; . Hãy thiết kế một hệ thống cấp bậc của các loài động vật mô phỏng đặc điểm này bằng cách in các âm thanh đặc trưng mà các loài động vật này tạo ra. Chúng tôi muốn thiết kế các lớp học của mình sao cho bất kỳ con vật nào cũng sẽ trả về một cái gì đó giống như “Tôi là một con bò và tôi đi moo,” khi chúng tôi gọi phương thức
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4. Hơn nữa, chúng tôi muốn thiết kế bộ sưu tập các lớp này sao cho nó có thể mở rộng—nghĩa là, để chúng tôi có thể tiếp tục thêm các loài động vật mới vào bầy thú của mình mà không phải thay đổi bất kỳ mã nào trong các lớp khácHình dưới đây cung cấp một bản tóm tắt về thiết kế chúng tôi sẽ thực hiện. Lớp
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
0 là một lớp trừu tượng. Đó là lý do tại sao tên của nó được in nghiêng trong hình. Lý do mà lớp này trừu tượng là vì phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
231 của nó là một phương thức trừu tượng, là một định nghĩa phương thức không chứa phần triển khai. Nghĩa là, định nghĩa phương thức chỉ chứa chữ ký của phương thức, không phải phần thân của nó. Bất kỳ lớp nào chứa một phương thức trừu tượng, chính nó phải được khai báo trừu tượngĐây là định nghĩa của lớp
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
0public String toString[] {
return "My name is " + name + " and I am a Student.";
}
21Lưu ý cách chúng ta khai báo phương thức trừu tượng [______1231] và lớp trừu tượng. Bởi vì một hoặc nhiều phương thức của nó không được triển khai, một lớp trừu tượng không thể được khởi tạo. Đó là, bạn không thể nói
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
22Mặc dù không cần thiết, chúng tôi cung cấp cho lớp Animal một hàm tạo. Nếu chúng ta bỏ qua điều này, Java sẽ cung cấp một hàm tạo mặc định sẽ được gọi khi các lớp con Animal được tạo
Java có các quy tắc sau về việc sử dụng các phương thức và lớp trừu tượng
- Bất kỳ lớp nào chứa phương thức trừu tượng phải được khai báo là một lớp
- Một lớp trừu tượng không thể được khởi tạo. Nó phải được phân lớp
- Một lớp con của một lớp trừu tượng chỉ có thể được khởi tạo nếu nó thực hiện tất cả các phương thức trừu tượng của lớp cha. Một lớp con chỉ thực hiện một số phương thức trừu tượng phải được khai báo trừu tượng
- Một lớp có thể được khai báo trừu tượng ngay cả khi nó không chứa các phương thức trừu tượng. Ví dụ, nó có thể chứa các biến thể hiện chung cho tất cả các lớp con của nó
Mặc dù một phương thức trừu tượng không được triển khai trong lớp cha, nhưng nó có thể được gọi trong lớp cha. Thật vậy, hãy lưu ý cách phương thức
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 gọi phương thức trừu tượng public String toString[] {
return "My name is " + name + " and I am a Student.";
}
231. Lý do điều này hoạt động trong Java là do cơ chế liên kết động. Phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
231 đa hình sẽ được định nghĩa trong các lớp con Animal khác nhau. Khi phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
237 được gọi, Java sẽ quyết định gọi phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
231 thực tế nào dựa trên lớp con của Animal có liên quanpublic String toString[] {
return "My name is " + name + " and I am a Student.";
}
23Trong mỗi trường hợp, lớp con mở rộng lớp
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
0 và cung cấp phương thức khởi tạo riêng và triển khai phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
231 của riêng nó. Lưu ý rằng trong các hàm tạo tương ứng của chúng, chúng ta có thể tham khảo biến thể hiện loại, được kế thừa từ lớp public String toString[] {
return "My name is " + name + " and I am a Student.";
}
0. Bằng cách khai báo loại là một biến được bảo vệ, nó được kế thừa bởi tất cả các lớp con của public String toString[] {
return "My name is " + name + " and I am a Student.";
}
0 nhưng bị ẩn khỏi tất cả các lớp khác. Mặt khác, nếu loại đã được khai báo công khai, nó sẽ được kế thừa bởi public String toString[] {
return "My name is " + name + " and I am a Student.";
}
0 lớp con, nhưng nó cũng có thể được truy cập bởi mọi lớp khác, điều này sẽ vi phạm nguyên tắc ẩn thông tinVới những định nghĩa này, giờ đây chúng ta có thể chứng minh sức mạnh và tính linh hoạt của tính kế thừa và tính đa hình. Xét đoạn mã sau
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
24Đầu tiên chúng ta tạo một đối tượng Cow và sau đó gọi phương thức [kế thừa]
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 của nó. Nó trả về, “Tôi là một con bò và tôi đi moo. ” Sau đó, chúng tôi tạo một đối tượng Cat và gọi phương thức [kế thừa] public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 của nó, phương thức này trả về, “Tôi là một con mèo và tôi kêu meo meo. ” Nói cách khác, Java có thể xác định cách triển khai speak[] thích hợp trong thời gian chạy trong từng trường hợp. Việc gọi phương thức speak[] trừu tượng trong phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
237 là một dạng đa hình thứ haiLợi thế của đa hình ở đây là gì? . Chúng ta có thể định nghĩa và sử dụng các lớp con Animal hoàn toàn mới mà không cần định nghĩa lại hoặc biên dịch lại các lớp còn lại trong hệ thống phân cấp. Lưu ý rằng phương thức
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 trong lớp Animal không cần biết loại lớp con Animal nào sẽ thực thi phương thức speak[] của nó. Phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 sẽ hoạt động chính xác cho bất kỳ lớp con nào của Animal vì mọi lớp con không trừu tượng của Animal phải triển khai phương thức speak[]Để đánh giá tốt hơn về tính linh hoạt và khả năng mở rộng của thiết kế này, có thể hữu ích khi xem xét một thiết kế thay thế không sử dụng tính đa hình. Một giải pháp thay thế như vậy là định nghĩa từng lớp con Động vật bằng phương thức nói của riêng nó. Một con Bò sẽ có phương thức moo[]; . Với thiết kế này, chúng ta có thể sử dụng câu lệnh switch để chọn phương thức gọi thích hợp. Ví dụ: xem xét định nghĩa phương thức sau
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
25Trong ví dụ này, chúng tôi giới thiệu toán tử
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
249, là toán tử boolean được tích hợp sẵn. Nó trả về true nếu đối tượng ở phía bên trái của nó là một thể hiện của lớp ở phía bên phải của nóPhương pháp
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
250 sẽ tạo ra kết quả ít nhiều giống nhau. Nếu bạn gọi talk[public String toString[] {
return "My name is " + name + " and I am a Student.";
}
251], nó sẽ trả về “I am a cow and I go moo. ” Tuy nhiên, với thiết kế này, không thể mở rộng phân cấp Animal mà không viết lại và biên dịch lại phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
250Do đó, một trong những ưu điểm chính của việc sử dụng tính đa hình là tính linh hoạt và khả năng mở rộng tuyệt vời mà nó mang lại. Chúng ta có thể định nghĩa các lớp con Animal mới và định nghĩa các phương thức
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
231 của chúng. Tất cả những thứ này sẽ hoạt động với phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4 trong lớp Động vật mà không cần phải sửa lại phương thức đóMột ưu điểm khác của việc sử dụng các phương thức trừu tượng là khả năng kiểm soát mà nó mang lại cho người thiết kế hệ thống phân cấp Động vật. Bằng cách biến nó thành một lớp trừu tượng với phương thức trừu tượng
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
231, bất kỳ lớp con Động vật không trừu tượng nào cũng phải triển khai phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
231. Điều này mang lại khả năng dự đoán cao cho các lớp con trong hệ thống phân cấp, giúp sử dụng chúng dễ dàng hơn trong các ứng dụngTheo các ví dụ trong phần này, hãy định nghĩa một phân lớp Động vật có tên là Lợn, lớp con này sẽ “oink. ”
Chỉ ra cách bạn sẽ phải sửa đổi phương thức
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
250 được xác định ở trên để kết hợp lớp PigTriển khai giao diện Java
Dạng đa hình thứ ba là kết quả thông qua việc triển khai các giao diện Java, giống như các lớp nhưng chỉ chứa các định nghĩa phương thức trừu tượng và các biến hằng [cuối cùng]. Một giao diện không thể chứa các biến thể hiện
Người thiết kế giao diện chỉ định phương thức nào sẽ được triển khai bởi các lớp triển khai giao diện. Điều này tương tự như những gì chúng ta đã làm khi triển khai phương thức speak[] trừu tượng trong ví dụ động vật. Sự khác biệt giữa việc triển khai một phương thức từ một giao diện và từ một lớp cha trừu tượng là một lớp con mở rộng một lớp cha trừu tượng nhưng nó thực thi một giao diện
Cơ chế giao diện của Java cho chúng ta một cách khác để thiết kế các phương thức đa hình. Để xem điều này hoạt động như thế nào, chúng tôi sẽ cung cấp một thiết kế thay thế cho hệ thống phân cấp động vật của chúng tôi. Thay vì định nghĩa speak[] như một phương thức trừu tượng trong lớp cha Animal, chúng ta sẽ định nghĩa nó như một phương thức trừu tượng trong giao diện Speakable
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
26Lưu ý sự khác biệt giữa định nghĩa Động vật này và định nghĩa trước đó. Phiên bản này không còn chứa phương thức trừu tượng
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
231. Do đó, bản thân lớp không phải là lớp trừu tượng. Tuy nhiên, vì phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
231 không được khai báo trong lớp này nên chúng ta không thể gọi phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
231 trong phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
4, trừ khi chúng ta ép kiểu đối tượng này thành đối tượng SpeakableVới những định nghĩa này, giờ đây các lớp con Animal sẽ mở rộng lớp Animal và triển khai giao diện Speakable
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
27Để triển khai giao diện Java, người ta phải cung cấp triển khai phương thức cho từng phương thức trừu tượng trong giao diện. Trong trường hợp này chỉ có một phương thức trừu tượng, phương thức speak[]
Lưu ý, một lần nữa, biểu thức từ Animal. lớp toString[]
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
28chuyển đối tượng này thành đối tượng
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
262. Lý do bắt buộc phải sử dụng phương thức này là vì Động vật không nhất thiết phải có phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
231. Một phương thức public String toString[] {
return "My name is " + name + " and I am a Student.";
}
231 không được định nghĩa trong lớp Animal. Tuy nhiên, lớp con Cat của Animal thực hiện phương thức sleep[] như một phần của giao diện Speakable của nó. Do đó, để gọi public String toString[] {
return "My name is " + name + " and I am a Student.";
}
231 trên một đối tượng từ một trong các lớp con Animal, đối tượng đó phải thực sự là một Speakable và chúng ta phải thực hiện ép kiểu như được hiển thị ở đâyNhân tiện, điều này minh họa rằng một
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
266, nhờ mở rộng lớp Animal và triển khai giao diện public String toString[] {
return "My name is " + name + " and I am a Student.";
}
262, vừa là một public String toString[] {
return "My name is " + name + " and I am a Student.";
}
0 vừa là một public String toString[] {
return "My name is " + name + " and I am a Student.";
}
262. Nói chung, một lớp thực hiện một giao diện, có giao diện đó là một trong các loại của nó. Bản thân việc triển khai giao diện là một hình thức kế thừa. Một lớp Java có thể là một lớp con trực tiếp của chỉ một lớp cha. Nhưng nó có thể thực hiện bất kỳ số lượng giao diện nàoVới các định nghĩa này của các lớp con
public String toString[] {
return "My name is " + name + " and I am a Student.";
}
270 và public String toString[] {
return "My name is " + name + " and I am a Student.";
}
266, đoạn mã sau sẽ tạo ra kết quả giống như trong phần trước