Mẹo Nếu một lớp chứa một phương thức trừu tượng ________.
Kinh Nghiệm Hướng dẫn Nếu một lớp chứa một phương thức trừu tượng ________. Mới Nhất
Bùi Thanh Tùng đang tìm kiếm từ khóa Nếu một lớp chứa một phương thức trừu tượng ________. được Cập Nhật vào lúc : 2022-12-02 00:14:07 . Với phương châm chia sẻ Thủ Thuật Hướng dẫn trong nội dung bài viết một cách Chi Tiết 2022. Nếu sau khi tham khảo nội dung bài viết vẫn ko hiểu thì hoàn toàn có thể lại phản hồi ở cuối bài để Ad lý giải và hướng dẫn lại nha.Các lớp trong Java tồn tại trong một khối mạng lưới hệ thống phân cấp. Một lớp trong Java hoàn toàn có thể được khai báo như một lớp con của một lớp khác bằng phương pháp sử dụng từ khóa
Cat simon = new Cat(); Animal creature = simon;0. Một lớp con thừa kế những biến và phương thức từ lớp cha của nó và hoàn toàn có thể sử dụng chúng như thể chúng được khai báo trong chính lớp con đó Nội dung chính Show- Các phương thức bị ghi đè và link độngphương pháp ở đầu cuối và hiệu suấtLựa chọn phương pháp xem xét lạiNgoại lệ và phương pháp ghi đèKiểu trả về và phương thức bị ghi đèTài liệu tham khảo đặc biệt. cái này và siêuSử dụng Superclass Constructortiết lộ đầy đủ. Constructor và khởi tạoCác phương thức và lớp trừu tượngmột quizlet lớp trừu tượng là gì?Khi một phương thức trong một lớp con có cùng chữ ký với một phương thức trong lớp cha thì nó?Điều gì là thiết yếu cho một phương thức giao diện có phần thân?Lớp con thừa kế gì từ lớp cha?
Trong ví dụ này, một đối tượng kiểu
Cat simon = new Cat(); Animal creature = simon;1 có cả biến thể hiện Cat simon = new Cat(); Animal creature = simon;2 và phương thức Cat simon = new Cat(); Animal creature = simon;3. Họ được thừa hưởng từ Cat simon = new Cat(); Animal creature = simon;4Một lớp chỉ hoàn toàn có thể mở rộng một lớp khác. Để sử dụng thuật ngữ thích hợp, Java được cho phép thừa kế duy nhất việc triển khai lớp. Ở phần sau của chương này, tất cả chúng ta sẽ nói về những giao diện, thay thế cho đa thừa kế vì nó đa phần được sử dụng trong những ngôn từ khác
Một phân lớp hoàn toàn có thể được phân lớp tiếp theo. Thông thường, phân lớp chuyên biệt hóa hoặc tinh chỉnh một lớp bằng phương pháp thêm những biến và phương thức (bạn không thể vô hiệu hoặc ẩn những biến hoặc phương thức bằng phương pháp phân lớp). Ví dụ
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ...Lớp
Cat simon = new Cat(); Animal creature = simon;5 là một loại Cat simon = new Cat(); Animal creature = simon;1 ở đầu cuối là một loại Cat simon = new Cat(); Animal creature = simon;4. Đối tượng Cat simon = new Cat(); Animal creature = simon;5 thừa kế tất cả những đặc điểm của đối tượng Cat simon = new Cat(); Animal creature = simon;1 và ngược lại, đối tượng Cat simon = new Cat(); Animal creature = simon;4. Cat simon = new Cat(); Animal creature = simon;5 cũng đáp ứng hành vi tương hỗ update dưới dạng phương thức class Animal float weight; ... void eat() ... ... class Mammal extends Animal // inherits weight int heartRate; ... // inherits eat() void breathe() ... 42 và biến class Animal float weight; ... void eat() ... ... class Mammal extends Animal // inherits weight int heartRate; ... // inherits eat() void breathe() ... 43. Chúng ta hoàn toàn có thể biểu thị quan hệ lớp trong sơ đồ, như trong Hình 6-1Một lớp con thừa kế tất cả những thành viên của lớp cha của nó không được chỉ định là
class Animal float weight; ... void eat() ... ... class Mammal extends Animal // inherits weight int heartRate; ... // inherits eat() void breathe() ... 44. Như tất cả chúng ta sẽ thảo luận ngay sau đây, những mức hiển thị khác ảnh hưởng đến việc những thành viên thừa kế của lớp hoàn toàn có thể được nhìn thấy từ bên phía ngoài lớp và những lớp con của nó, nhưng ở mức tối thiểu, một lớp con luôn có cùng một tập hợp những thành viên hiển thị như lớp cha của nó. Vì nguyên do này, loại của một lớp con hoàn toàn có thể được xem là một kiểu con của lớp cha của nó và những thể hiện của kiểu con hoàn toàn có thể được sử dụng ở bất kỳ nơi nào được cho phép những thể hiện của siêu kiểu. Xem xét ví dụ sau Cat simon = new Cat(); Animal creature = simon;Hình 6-1. Một khối mạng lưới hệ thống phân cấp lớp
Ví dụ
Cat simon = new Cat(); Animal creature = simon;5 class Animal float weight; ... void eat() ... ... class Mammal extends Animal // inherits weight int heartRate; ... // inherits eat() void breathe() ... 46 trong ví dụ này hoàn toàn có thể được gán cho biến loại Cat simon = new Cat(); Animal creature = simon;4 class Animal float weight; ... void eat() ... ... class Mammal extends Animal // inherits weight int heartRate; ... // inherits eat() void breathe() ... 48 vì Cat simon = new Cat(); Animal creature = simon;5 là một kiểu con của Cat simon = new Cat(); Animal creature = simon;4. Tương tự, bất kỳ phương thức nào đồng ý một đối tượng Cat simon = new Cat(); Animal creature = simon;4 cũng tiếp tục đồng ý một thể hiện của một loại Cat simon = new Cat(); Animal creature = simon;5 hoặc bất kỳ loại Cat simon = new Cat(); Animal creature = simon;1 nào. Đây là một khía cạnh quan trọng của tính đa hình trong một ngôn từ hướng đối tượng như Java. Chúng ta sẽ xem nó hoàn toàn có thể được sử dụng ra làm sao để tinh chỉnh hành vi của một lớp, cũng như thêm những kĩ năng mới cho lớp đóTrong Chương 5, tất cả chúng ta đã thấy rằng một biến cục bộ cùng tên với một biến thể hiện sẽ che (ẩn) biến thể hiện. Tương tự, một biến thể hiện trong một lớp con hoàn toàn có thể che khuất một biến thể hiện cùng tên trong lớp cha của nó, như minh họa trong Hình 6-2. Chúng tôi sẽ đề cập rõ ràng về ẩn biến này ngay giờ đây để hoàn thiện và sẵn sàng sẵn sàng cho những chủ đề nâng cao hơn, nhưng trong thực tế, bạn hầu như không bao giờ nên làm điều này. Trên thực tế, sẽ tốt hơn nhiều nếu cấu trúc mã của bạn để phân biệt rõ ràng những biến bằng phương pháp sử dụng những tên hoặc quy ước đặt tên rất khác nhau
Trong Hình 6-2, biến
Cat simon = new Cat(); Animal creature = simon;2 được khai báo ở ba vị trí. dưới dạng biến cục bộ trong phương thức Cat simon = new Cat(); Animal creature = simon;85 của lớp Cat simon = new Cat(); Animal creature = simon;1, dưới dạng biến thể hiện của lớp Cat simon = new Cat(); Animal creature = simon;1 và dưới dạng biến thể hiện của lớp Cat simon = new Cat(); Animal creature = simon;4. Biến thực tế được chọn khi bạn tham chiếu nó trong mã sẽ phụ thuộc vào phạm vi mà chúng tôi đang thao tác và cách bạn đủ điều kiện tham chiếu đến nóHình 6-2. Phạm vi của những biến bóng mờ
Trong ví dụ trước, tất cả những biến đều cùng loại. Việc sử dụng những biến bóng mờ hợp lý hơn một chút ít sẽ liên quan đến việc thay đổi loại của chúng. Ví dụ, tất cả chúng ta hoàn toàn có thể tạo bóng một biến
Cat simon = new Cat(); Animal creature = simon;89 với một biến Cat simon = new Cat(); Animal creature = simon;30 trong một lớp con cần giá trị thập phân thay vì giá trị số nguyên. Chúng tôi hoàn toàn có thể làm điều này mà không cần thay đổi mã hiện có chính bới, như tên gọi của nó, khi chúng tôi ẩn những biến, chúng tôi không thay thế chúng mà thay vào đó che giấu chúng. Cả hai biến vẫn tồn tại; . Việc xác định những biến mà những phương thức rất khác nhau nhìn thấy xảy ra tại thời điểm biên dịchĐây là một ví dụ đơn giản
class Animal float weight; ... void eat() ... ... class Mammal extends Animal // inherits weight int heartRate; ... // inherits eat() void breathe() ... 4Trong ví dụ này, chúng tôi tạo bóng cho biến thể hiện
Cat simon = new Cat(); Animal creature = simon;31 để thay đổi loại của nó từ Cat simon = new Cat(); Animal creature = simon;89 thành Cat simon = new Cat(); Animal creature = simon;30. [] Các phương thức được định nghĩa trong lớp Cat simon = new Cat(); Animal creature = simon;34 xem biến số nguyên Cat simon = new Cat(); Animal creature = simon;31, trong khi những phương thức được định nghĩa trong lớp Cat simon = new Cat(); Animal creature = simon;36 xem biến dấu phẩy động Cat simon = new Cat(); Animal creature = simon;31. Tuy nhiên, cả hai biến thực sự tồn tại trong một phiên bản nhất định của Cat simon = new Cat(); Animal creature = simon;36 và chúng hoàn toàn có thể có những giá trị độc lập. Trên thực tế, bất kỳ phương thức nào mà Cat simon = new Cat(); Animal creature = simon;36 thừa kế từ Cat simon = new Cat(); Animal creature = simon;34 đều thực sự nhìn thấy biến số nguyên Cat simon = new Cat(); Animal creature = simon;31Bởi vì cả hai biến đều tồn tại trong
Cat simon = new Cat(); Animal creature = simon;36, nên tất cả chúng ta cần một phương pháp để tham chiếu biến thừa kế từ Cat simon = new Cat(); Animal creature = simon;34. Chúng tôi làm điều đó bằng phương pháp sử dụng từ khóa Cat simon = new Cat(); Animal creature = simon;84 làm từ hạn định trên tài liệu tham khảo Cat simon = new Cat(); Animal creature = simon;8Bên trong
Cat simon = new Cat(); Animal creature = simon;36, từ khóa Cat simon = new Cat(); Animal creature = simon;84 được sử dụng theo cách này sẽ chọn biến Cat simon = new Cat(); Animal creature = simon;31 được xác định trong siêu lớp. Chúng tôi sẽ lý giải việc sử dụng Cat simon = new Cat(); Animal creature = simon;84 đầy đủ hơn một chút ítMột điểm quan trọng khác về những biến bóng mờ liên quan đến cách chúng hoạt động và sinh hoạt giải trí khi tất cả chúng ta tham chiếu đến một đối tượng bằng một kiểu ít dẫn xuất hơn (kiểu cha). Ví dụ, tất cả chúng ta hoàn toàn có thể gọi một đối tượng
Cat simon = new Cat(); Animal creature = simon;36 là một Cat simon = new Cat(); Animal creature = simon;34 bằng phương pháp sử dụng nó thông qua một biến kiểu Cat simon = new Cat(); Animal creature = simon;34. Nếu tất cả chúng ta làm như vậy và sau đó truy cập vào biến Cat simon = new Cat(); Animal creature = simon;31, tất cả chúng ta sẽ nhận được biến số nguyên chứ không phải số thập phân Cat simon = new Cat(); Animal creature = simon;3Điều này cũng đúng nếu tất cả chúng ta truy cập đối tượng bằng phương pháp truyền rõ ràng sang kiểu
Cat simon = new Cat(); Animal creature = simon;34 hoặc khi chuyển một thể hiện vào một phương thức đồng ý kiểu cha đóĐể nhắc lại, tính hữu ích của những biến bóng tối bị hạn chế. Tốt hơn hết là trừu tượng hóa việc sử dụng những biến như vậy này theo những cách khác hơn là sử dụng những quy tắc phạm vi phức tạp. Tuy nhiên, điều quan trọng là phải hiểu những khái niệm ở đây trước khi tất cả chúng ta nói về việc làm điều tương tự với những phương thức. Chúng ta sẽ thấy một loại hành vi khác và năng động hơn khi những phương thức che khuất những phương thức khác hoặc sử dụng thuật ngữ đúng chuẩn, ghi đè những phương thức khác
Trong Chương 5, tất cả chúng ta đã thấy rằng tất cả chúng ta hoàn toàn có thể khai báo những phương thức quá tải (i. e. , những phương thức có cùng tên nhưng khác số lượng hoặc kiểu đối số) trong một lớp. Lựa chọn phương thức quá tải hoạt động và sinh hoạt giải trí theo cách chúng tôi đã mô tả trên tất cả những phương thức có sẵn cho một lớp, gồm có cả những phương thức thừa kế. Điều này nghĩa là một lớp con hoàn toàn có thể định nghĩa những phương thức quá tải tương hỗ update thêm vào những phương thức quá tải được đáp ứng bởi một lớp cha
Một lớp con hoàn toàn có thể làm nhiều hơn nữa thế; . Trong trường hợp đó, phương thức trong lớp con sẽ ghi đè phương thức trong lớp cha và thay thế hiệu suất cao việc triển khai của nó, như minh họa trong Hình 6-3. Ghi đè những phương thức để thay đổi hành vi của những đối tượng được gọi là đa hình kiểu con. Đó là cách sử dụng mà hầu hết mọi người nghĩ đến khi họ nói về sức mạnh mẽ và tự tin của ngôn từ hướng đối tượng
Hình 6-3. Ghi đè phương thức
Trong Hình 6-3,
Cat simon = new Cat(); Animal creature = simon;1 thay thế phương pháp class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 15 của Cat simon = new Cat(); Animal creature = simon;4, có lẽ rằng để chuyên biệt hóa phương pháp cho hành vi của động vật có vú sinh con. [] Hành vi ngủ của đối tượng Cat simon = new Cat(); Animal creature = simon;5 cũng khá được ghi đè để khác với hành vi của đối tượng Cat simon = new Cat(); Animal creature = simon;4 chung, có lẽ rằng để phù phù phù hợp với giấc ngủ ngắn của mèo. Lớp Cat simon = new Cat(); Animal creature = simon;5 cũng tương hỗ update những hành vi rừ rừ và săn chuột độc đáo hơnTừ những gì bạn đã thấy cho tới nay, những phương thức bị ghi đè hoàn toàn có thể trông in như những phương thức ẩn trong những lớp cha, in như những biến vậy. Nhưng những phương thức bị ghi đè thực sự mạnh hơn thế. Khi có nhiều triển khai của một phương thức trong khối mạng lưới hệ thống phân cấp thừa kế của một đối tượng, thì phương thức trong lớp “có nguồn gốc cao nhất” (xa nhất trong khối mạng lưới hệ thống phân cấp) luôn ghi đè lên những phương thức khác, trong cả những lúc tất cả chúng ta tham chiếu đến đối tượng thông qua tham chiếu của một trong những . []
Ví dụ: nếu tất cả chúng ta có một thể hiện
Cat simon = new Cat(); Animal creature = simon;5 được gán cho một biến có kiểu tổng quát hơn là Cat simon = new Cat(); Animal creature = simon;4 và tất cả chúng ta gọi phương thức class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 82 của nó, thì tất cả chúng ta vẫn nhận được phương thức class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 82 được triển khai trong lớp Cat simon = new Cat(); Animal creature = simon;5, không phải phương thức trong lớp Cat simon = new Cat(); Animal creature = simon;4 Cat simon = new Cat(); Animal creature = simon;8Nói cách khác, đối với những mục tiêu của hành vi (những phương thức gọi), một
Cat simon = new Cat(); Animal creature = simon;5 hoạt động và sinh hoạt giải trí in như một Cat simon = new Cat(); Animal creature = simon;5, bất kể bạn có gọi nó như vậy hay là không. Ở khía cạnh khác, biến class Animal float weight; ... void eat() ... ... class Mammal extends Animal // inherits weight int heartRate; ... // inherits eat() void breathe() ... 48 ở đây hoàn toàn có thể hoạt động và sinh hoạt giải trí in như một tham chiếu Cat simon = new Cat(); Animal creature = simon;4. Như chúng tôi đã lý giải trước đó, việc truy cập vào một biến bị che khuất thông qua tham chiếu Cat simon = new Cat(); Animal creature = simon;4 sẽ tìm thấy một triển khai trong lớp Cat simon = new Cat(); Animal creature = simon;4, không phải lớp Cat simon = new Cat(); Animal creature = simon;5. Tuy nhiên, vì những phương thức được định vị một cách linh hoạt, tìm kiếm những lớp con trước tiên, nên phương thức thích hợp trong lớp Cat simon = new Cat(); Animal creature = simon;5 được gọi, tuy nhiên tất cả chúng ta đang xử lý nó một cách tổng quát hơn như một đối tượng Cat simon = new Cat(); Animal creature = simon;4. Điều này nghĩa là hành vi của những đối tượng là động. Chúng ta hoàn toàn có thể xử lý những đối tượng chuyên biệt như thể chúng là nhiều chủng loại tổng quát hơn và vẫn tận dụng lợi thế của việc triển khai hành vi chuyên biệt của chúngMột lỗi lập trình phổ biến trong Java là vô tình làm quá tải một phương thức khi nỗ lực ghi đè lên nó. Bất kỳ sự khác lạ nào về số lượng hoặc loại đối số (chữ ký của phương thức) sẽ tạo ra hai phương thức bị quá tải thay vì một phương thức bị ghi đè. Cú pháp chú thích mới trong Java 5. 0 đáp ứng một phương pháp để trình biên dịch trợ giúp vấn đề này. Chú thích, như chúng tôi sẽ mô tả trong Chương 7, được cho phép chúng tôi thêm những điểm đánh dấu hoặc siêu tài liệu đặc biệt vào mã nguồn mà trình biên dịch hoặc công cụ thời gian chạy hoàn toàn có thể đọc được. Một trong những chú thích tiêu chuẩn mà Java định nghĩa được gọi là
Cat simon = new Cat(); Animal creature = simon;25 và nó cho trình biên dịch biết rằng phương thức mà nó đánh dấu nhằm mục đích ghi đè lên một phương thức trong lớp cha. Sau đó, trình biên dịch sẽ chú ý nếu phương thức không khớp. Ví dụ: tất cả chúng ta hoàn toàn có thể chỉ định rằng phương thức class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 82 của lớp Cat simon = new Cat(); Animal creature = simon;5 của tất cả chúng ta sẽ ghi đè một phương thức trong lớp cha như vậy class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 1Các phương thức bị ghi đè và link động
Trong phần trước, chúng tôi đã đề cập rằng những phương thức quá tải được trình biên dịch chọn tại thời điểm biên dịch. Mặt khác, những phương thức bị ghi đè được chọn động khi chạy. Ngay cả khi tất cả chúng ta tạo một thể hiện của một phân lớp mà mã của tất cả chúng ta trước đó chưa từng thấy trước đây (có lẽ rằng là một lớp mới được tải qua mạng), thì bất kỳ phương thức ghi đè nào chứa trong đó đều được định vị và sử dụng trong thời gian chạy, thay thế những phương thức đã tồn tại khi tất cả chúng ta biên dịch mã lần cuối
trái lại, nếu tất cả chúng ta tạo một lớp mới triển khai một phương thức quá tải tương hỗ update, rõ ràng hơn và thay thế lớp đã biên dịch trong đường dẫn lớp của tất cả chúng ta bằng phương thức đó, thì mã của tất cả chúng ta sẽ tiếp tục sử dụng cách triển khai mà nó đã mày mò ban đầu. Tình trạng này sẽ tiếp tục cho tới lúc chúng tôi biên dịch lại mã của tớ cùng với lớp mới. Một hiệu ứng khác của điều này là việc truyền (i. e. , thông báo rõ ràng cho trình biên dịch coi một đối tượng là một trong những kiểu hoàn toàn có thể gán của nó) ảnh hưởng đến việc lựa chọn những phương thức quá tải tại thời điểm biên dịch nhưng không ảnh hưởng đến những phương thức bị ghi đè
Trong thực tế, những gì chúng tôi vừa mô tả không phải là vấn đề bạn nên phải lo ngại thường xuyên, nhưng điều quan trọng là phải hiểu máy ảo làm gì và không làm gì trong thời gian chạy.
Các phương thức tĩnh không thuộc về bất kỳ đối tượng nào; . Đó là nguyên do tại sao những phương thức tĩnh được gọi là "tĩnh";
Một phương thức tĩnh trong lớp cha hoàn toàn có thể bị che khuất bởi một phương thức tĩnh khác trong lớp con, miễn là phương thức ban đầu không được khai báo là ở đầu cuối. Tuy nhiên, cả hai phương thức luôn hoàn toàn có thể truy cập trực tiếp thông qua tên lớp tương ứng của chúng. Bạn không thể "ghi đè" một phương thức tĩnh bằng một phương thức thể hiện. Nói cách khác, bạn không thể có một phương thức tĩnh và một phương thức thể hiện có cùng chữ ký trong cùng một khối mạng lưới hệ thống phân cấp lớp
phương pháp ở đầu cuối và hiệu suất
Trong những ngôn từ như C++, mặc định là những phương thức hoạt động và sinh hoạt giải trí in như những biến ẩn, vì vậy bạn phải khai báo rõ ràng những phương thức bạn muốn là động (hoặc, như C++ gọi chúng là ảo). Trong Java, những phương thức thể hiện, theo mặc định, là động. Nhưng bạn hoàn toàn có thể sử dụng công cụ sửa đổi
Cat simon = new Cat(); Animal creature = simon;28 để tuyên bố rằng một phương thức thể hiện không thể bị ghi đè trong một lớp con và nó sẽ không biến thành ràng buộc độngChúng ta đã thấy
Cat simon = new Cat(); Animal creature = simon;28 được sử dụng với những biến để biến chúng thành hằng số một cách hiệu suất cao. Khi được áp dụng cho một phương thức, Cat simon = new Cat(); Animal creature = simon;28 nghĩa là việc triển khai của nó không đổi—không được cho phép ghi đè. Cat simon = new Cat(); Animal creature = simon;28 cũng hoàn toàn có thể được áp dụng cho toàn bộ lớp, điều đó nghĩa là lớp không thể được phân lớpTrước đây, link phương thức động đi kèm với một hình phạt hiệu suất đáng kể và một số trong những người dân vẫn có xu hướng sử dụng công cụ sửa đổi
Cat simon = new Cat(); Animal creature = simon;28 để bảo vệ chống lại điều này. Các khối mạng lưới hệ thống thời gian chạy Java tân tiến vô hiệu nhu yếu về loại tinh chỉnh này. Thời gian chạy định hình hoàn toàn có thể xác định phương thức nào không biến thành ghi đè và "sáng sủa" nội tuyến chúng, xử lý chúng như thể chúng là phương thức ở đầu cuối cho tới lúc thiết yếu phải làm khác. Theo quy định, bạn nên sử dụng từ khóa Cat simon = new Cat(); Animal creature = simon;28 khi nó phù phù phù hợp với cấu trúc chương trình của bạn, không phải để xem xét hiệu suấtTrong một số trong những phiên bản Java cũ hơn, trình biên dịch javac hoàn toàn có thể được chạy với khóa -O, lệnh này yêu cầu trình biên dịch thực hiện một số trong những tối ưu hóa nhất định, như nội tuyến, tĩnh. Hầu hết những tối ưu hóa này hiện được thực hiện trong thời gian chạy bởi những máy ảo thông minh hơn, do đó, những quy đổi như vậy này thường không thiết yếu
Một loại tối ưu hóa khác được cho phép bạn đưa mã gỡ lỗi vào nguồn Java của tớ mà không biến thành phạt về kích thước hoặc hiệu suất. Mặc dù Java không còn bộ tiền xử lý để trấn áp rõ ràng nguồn nào được đưa vào, nhưng bạn hoàn toàn có thể nhận được một số trong những tác dụng tương tự bằng phương pháp đặt một khối mã có điều kiện trên một hằng số (i. e. ,
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 04 và Cat simon = new Cat(); Animal creature = simon;28) biến. Trình biên dịch Java đủ thông minh để vô hiệu mã này khi nó xác định rằng nó sẽ không được gọi. Ví dụ class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 8Trong trường hợp này, trình biên dịch hoàn toàn có thể nhận ra rằng điều kiện trên biến ________ 606 luôn là ________ 607 và phần thân của phương thức
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 08 sẽ được tối ưu hóa. Với trình biên dịch tân tiến, lệnh gọi phương thức thậm chí hoàn toàn có thể được tối ưu hóa hoàn toànLưu ý rằng loại mã gỡ lỗi này hữu ích cho những mục tiêu như ghi nhật ký. trái lại với những xác nhận mà chúng tôi đã đề cập trong Chương 4, được cho là những kiểm tra có/không nhằm mục đích đảm bảo tính đúng chuẩn của logic chương trình của bạn, những khối mã có điều kiện này hoàn toàn có thể thực hiện định dạng đắt tiền hoặc xử lý đầu ra khác hữu ích trong quá trình phát triển nhưng bạn
Lựa chọn phương pháp xem xét lại
Bây giờ bạn đã có một cảm hứng tốt, trực quan về cách những phương thức được chọn từ nhóm những tên phương thức hoàn toàn có thể bị quá tải và bị ghi đè của một lớp. Tuy nhiên, nếu bạn muốn biết thêm rõ ràng, chúng tôi sẽ đáp ứng ngay giờ đây
Trong phần trước, tất cả chúng ta đã đưa ra một quy nạp quy nạp để xử lý và xử lý phương thức quá tải. Nó nói rằng một phương thức được xem là rõ ràng hơn một phương thức khác nếu những đối số của nó hoàn toàn có thể gán được cho những đối số của phương thức thứ hai. Bây giờ tất cả chúng ta hoàn toàn có thể mở rộng quy tắc này để gồm có việc xử lý và xử lý những phương thức bị ghi đè bằng phương pháp thêm điều kiện sau. để rõ ràng hơn một phương thức khác, loại lớp chứa phương thức này cũng phải được gán cho loại lớp chứa phương thức thứ hai
Điều đó nghĩa là gì? . Bởi vì nhiều chủng loại lớp con hoàn toàn có thể gán cho những loại lớp cha, nhưng không phải ngược lại, độ phân giải được đẩy theo cách mà chúng tôi mong đợi xuống chuỗi đối với những lớp con. Điều này tương hỗ update một cách hiệu suất cao chiều thứ hai cho tìm kiếm, trong đó độ phân giải được đẩy xuống cây thừa kế đối với những lớp được tinh chỉnh hơn và đồng thời hướng tới phương thức quá tải rõ ràng nhất trong một lớp nhất định
Ngoại lệ và phương pháp ghi đè
Một phương thức ghi đè hoàn toàn có thể thay đổi hành vi của một đối tượng, nhưng theo một số trong những cách, nó vẫn phải thực hiện hợp đồng của phương thức ban đầu với người tiêu dùng. Cụ thể, một phương thức ghi đè phải tuân thủ mệnh đề
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 09 của phương thức ban đầu. Phương thức mới không thể ném nhiều chủng loại ngoại lệ được kiểm tra mới. Nó chỉ hoàn toàn có thể tuyên bố rằng nó ném nhiều chủng loại ngoại lệ hoàn toàn có thể gán cho những loại được ném bởi phương thức trong lớp cha; . Nếu phương thức mới không đưa ra bất kỳ ngoại lệ đã kiểm tra nào của bản gốc, thì nó không phải khai báo chúng và những người dân gọi phương thức thông qua lớp con không phải đề phòng chúng. (Bằng cách này, bạn hoàn toàn có thể ghi đè lên một phương thức để “xử lý” những ngoại lệ cho những người dân tiêu dùng. )Vì vậy, phương thức mới hoàn toàn có thể khai báo đúng chuẩn những ngoại lệ được kiểm tra in như phương thức ban đầu hoặc nó có tùy chọn để tinh chỉnh nhiều chủng loại đó bằng phương pháp tuyên bố rằng nó đưa ra những kiểu con rõ ràng hơn so với phương thức đã ghi đè. Điều này sẽ không in như việc chỉ nói rằng phương thức hoàn toàn có thể đơn giản ném những kiểu con của những ngoại lệ đã khai báo của nó; . Phương pháp mới thực sự hoàn toàn có thể xác định lại mệnh đề
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 09 của phương pháp rõ ràng hơn. Kỹ thuật này được gọi là gõ hiệp biến của mệnh đề class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 09, nghĩa là nhiều chủng loại ngoại lệ mà người tiêu dùng phải bảo vệ thay đổi để trở nên tinh tế hơn với loại phụHãy nhanh gọn xem lại mệnh đề
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 09 thực sự nghĩa là gì. Nếu một phương thức tuyên bố rằng nó hoàn toàn có thể ném ra một class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 13, thì điều đó thực sự nói rằng nó hoàn toàn có thể ném ra những ngoại lệ kiểu class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 13 hoặc những kiểu con của nó. Ví dụ, class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 15 là một loại của class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 13. Một phương thức tuyên bố rằng nó hoàn toàn có thể ném class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 13 thực sự hoàn toàn có thể ném class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 15 hoặc bất kỳ kiểu con nào khác của class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 13 khi chạy Cat simon = new Cat(); Animal creature = simon;2Khi tất cả chúng ta gọi phương thức này, trình biên dịch sẽ đảm nói rằng tất cả chúng ta được cho phép kĩ năng xảy ra bất kỳ loại
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 13 nào, bằng phương pháp sử dụng khối class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 21 hoặc bằng phương pháp ném ngoại lệ từ phương thức của tất cả chúng taKhi tất cả chúng ta ghi đè một phương thức trong một lớp con, tất cả chúng ta có thời cơ viết lại mệnh đề
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 09 của phương thức một chút ít. Phương thức mới vẫn phải tương thích ngược với phương thức ban đầu, vì vậy mọi ngoại lệ được kiểm tra mà nó ném ra phải được gán cho những ngoại lệ được ném bởi phương thức bị ghi đè. Nhưng tất cả chúng ta hoàn toàn có thể rõ ràng hơn nếu muốn, tinh chỉnh loại ngoại lệ để phù phù phù hợp với hành vi của phương thức mới. Ví dụ class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 0Trong mã này,
Cat simon = new Cat(); Animal creature = simon;4 xác định rằng nó hoàn toàn có thể ném một class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 24 từ phương thức Cat simon = new Cat(); Animal creature = simon;3 của nó. class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 26 là một lớp con của Cat simon = new Cat(); Animal creature = simon;4, vì vậy phương thức Cat simon = new Cat(); Animal creature = simon;3 của nó cũng phải hoàn toàn có thể ném một class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 24. Tuy nhiên, phương thức Cat simon = new Cat(); Animal creature = simon;3 của class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 26 thực sự tuyên bố rằng nó ném ra một ngoại lệ rõ ràng hơn. class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 32. Nó hoàn toàn có thể làm điều này vì class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 32 là một kiểu con của class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 24. Nếu tất cả chúng ta đang thao tác trực tiếp với một loại class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 26, trình biên dịch sẽ được cho phép tất cả chúng ta chỉ bắt được loại class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 32 và không yêu cầu tất cả chúng ta đề phòng loại chung chung hơn là class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 24 class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 1Mặt khác, nếu chúng tôi không quan tâm tại sao thực phẩm không ăn được, chúng tôi hoàn toàn có thể tự do bảo vệ
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 24 chung chung hơn và coi nó như bất kỳ Cat simon = new Cat(); Animal creature = simon;4 nào khácTóm lại, một phương thức ghi đè hoàn toàn có thể tinh chỉnh không riêng gì có hành vi của phương thức cha mà còn cả loại ngoại lệ được kiểm tra mà nó đưa ra. Tiếp theo, tất cả chúng ta sẽ nói về những phương thức bị ghi đè thay đổi kiểu trả về của chúng theo cùng một cách
Kiểu trả về và phương thức bị ghi đè
Để một phương thức đủ điều kiện là một phương thức được ghi đè trong một lớp con, phương thức đó phải có cùng số lượng và loại đối số. Nó phải có cùng “đầu vào” như nó vốn có. Như tất cả chúng ta đã thấy trong phần trước, những phương thức ghi đè hoàn toàn có thể tinh chỉnh “đầu ra” của chúng ở một mức độ nào đó. Cụ thể, họ hoàn toàn có thể thu hẹp mệnh đề
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 09 của tớ bằng phương pháp tuyên bố rằng họ ném những kiểu con của những kiểu ngoại lệ của phương thức ban đầu. Còn “đầu ra” chính của một phương pháp thì sao?Điều này nghĩa là lúc bạn ghi đè một phương thức, bạn hoàn toàn có thể thay đổi kiểu trả về thành kiểu con của kiểu trả về của phương thức ban đầu. Ví dụ: nếu lớp
Cat simon = new Cat(); Animal creature = simon;4 của chúng tôi có một phương thức xuất xưởng mang tên là class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 42 tạo ra một thể hiện của Cat simon = new Cat(); Animal creature = simon;4, thì lớp Cat simon = new Cat(); Animal creature = simon;1 của chúng tôi hoàn toàn có thể tinh chỉnh kiểu trả về thành Cat simon = new Cat(); Animal creature = simon;1 class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 2Như tất cả chúng ta sẽ thấy ở phần sau, kỹ thuật viết mã này rất hữu ích vì nó vô hiệu một số trong những thao tác truyền đối tượng trong thời gian chạy.
Tài liệu tham khảo đặc biệt. cái này và siêu
Các tham chiếu đặc biệt
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 46 và Cat simon = new Cat(); Animal creature = simon;84 được cho phép bạn lần lượt tham chiếu đến những thành viên của thể hiện đối tượng hiện tại hoặc những thành viên của lớp cha. Chúng ta đã thấy class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 46 được sử dụng ở những nơi khác để truyền tham chiếu đến đối tượng hiện tại và để tham chiếu đến những biến thể hiện bị che khuất. Tham chiếu Cat simon = new Cat(); Animal creature = simon;84 cũng làm như vậy đối với phụ huynh của một lớp. Bạn hoàn toàn có thể sử dụng nó để chỉ những thành viên của một siêu lớp đã bị che khuất hoặc bị ghi đè. Khả năng gọi phương thức ban đầu của lớp cha được cho phép tất cả chúng ta sử dụng nó như một phần của phương thức mới, ủy quyền cho hành vi của nó trước hoặc sau khi tất cả chúng ta thực hiện việc làm tương hỗ update class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 3Trong ví dụ này, lớp
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 26 của tất cả chúng ta ghi đè phương thức ________ 651 để trước tiên thực hiện một số trong những kiểm tra trên đối tượng ________ 652. Sau khi thực hiện việc làm của tớ, nó sử dụng class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 53 để gọi triển khai (nếu không sẽ bị ghi đè và không thể truy cập được) của Cat simon = new Cat(); Animal creature = simon;3 trong lớp cha của nó Cat simon = new Cat(); Animal creature = simon;84 nhắc tìm kiếm phương thức hoặc biến khởi đầu trong phạm vi của lớp cha trực tiếp thay vì lớp hiện tại. Phương thức hoặc biến được thừa kế được tìm thấy hoàn toàn có thể nằm trong lớp cha trực tiếp hoặc một lớp tiếp theo trên cây. Việc sử dụng tham chiếu Cat simon = new Cat(); Animal creature = simon;84 khi được áp dụng cho những phương thức được ghi đè của lớp cha là đặc biệt; . Không có Cat simon = new Cat(); Animal creature = simon;84, sẽ không còn cách nào để truy cập những phương thức bị ghi đèMột diễn viên yêu cầu trình biên dịch thay đổi loại rõ ràng của một tham chiếu đối tượng. Công dụng chính của ép kiểu là lúc một đối tượng tạm thời được gán cho một kiểu tổng quát hơn. Ví dụ: nếu một
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 58 được gán cho một biến loại class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 59, để sử dụng lại nó như một class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 58, tất cả chúng ta phải thực hiện ép kiểu để lấy lại nó. Trình biên dịch chỉ nhận ra nhiều chủng loại biến được khai báo và không biết rằng tất cả chúng ta đã thực sự đặt một class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 58 vào đó. Trong Java, những diễn viên được kiểm tra cả khi biên dịch và khi chạy để đảm nói rằng chúng hợp pháp. Tại thời điểm biên dịch, trình biên dịch Java sẽ ngăn bạn nỗ lực thực hiện một phép ép kiểu không thể hoạt động và sinh hoạt giải trí (ví dụ như chuyển trực tiếp một class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 62 thành một class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 58). Và trong thời gian chạy, Java sẽ kiểm tra xem những phôi có hợp lý không (ví dụ như class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 59 đến class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 58 của chúng tôi) có thực sự đúng chuẩn đối với những đối tượng thực có liên quan hay là khôngCố gắng truyền một đối tượng sang một loại không tương thích trong thời gian chạy sẽ dẫn đến ____666
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 67 class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 68. Chỉ những phép truyền Một trong những đối tượng trong cùng một khối mạng lưới hệ thống phân cấp thừa kế (và, như tất cả chúng ta sẽ thấy sau, với những giao diện phù hợp) là hợp pháp trong Java và vượt qua sự giám sát kỹ lưỡng của trình biên dịch và khối mạng lưới hệ thống thời gian chạy. Diễn viên trong Java chỉ ảnh hưởng đến việc xử lý những tham chiếu; . Đây là một quy tắc quan trọng cần ghi nhớ. Bạn không bao giờ thay đổi đối tượng được trỏ tới bởi một tham chiếu bằng phương pháp ép kiểu nó;Có thể sử dụng phép truyền để thu hẹp hoặc hạ thấp loại tham chiếu—để làm cho nó rõ ràng hơn. Thông thường, chúng tôi sẽ làm điều này khi chúng tôi phải truy xuất một đối tượng từ một loại bộ sưu tập tổng quát hơn hoặc khi nó đã được sử dụng trước đó như một loại ít dẫn xuất hơn. (Ví dụ nguyên mẫu đang sử dụng một đối tượng trong bộ sưu tập, như tất cả chúng ta sẽ thấy trong Chương 11. ) Tiếp tục với ví dụ về
Cat simon = new Cat(); Animal creature = simon;5 của tất cả chúng ta class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 4Chúng ta không thể gán lại tham chiếu trong
class Animal float weight; ... void eat() ... ... class Mammal extends Animal // inherits weight int heartRate; ... // inherits eat() void breathe() ... 48 cho biến class Animal float weight; ... void eat() ... ... class Mammal extends Animal // inherits weight int heartRate; ... // inherits eat() void breathe() ... 46 tuy nhiên tất cả chúng ta biết rằng nó chứa một thể hiện của một Cat simon = new Cat(); Animal creature = simon;5 (Simon). Chúng ta phải thực hiện ép kiểu được chỉ định để thu hẹp tham chiếu. Lưu ý rằng một phép gán ẩn đã được thực hiện khi chúng tôi thực hiện theo cách khác để mở rộng tham chiếu class Animal float weight; ... void eat() ... ... class Mammal extends Animal // inherits weight int heartRate; ... // inherits eat() void breathe() ... 46 thành loại Cat simon = new Cat(); Animal creature = simon;4 trong lần gán đầu tiên. Trong trường hợp này, một diễn viên rõ ràng sẽ hợp pháp nhưng không thiết yếuTất cả điều này nghĩa là bạn không thể nói dối hoặc đoán về một đối tượng. Nếu bạn có một đối tượng
Cat simon = new Cat(); Animal creature = simon;5, bạn hoàn toàn có thể sử dụng nó như một Cat simon = new Cat(); Animal creature = simon;4 hoặc thậm chí là ________ 659 vì tất cả những lớp Java đều là lớp con của ________ 659. Nhưng nếu bạn có một class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 59 mà bạn nghĩ là một Cat simon = new Cat(); Animal creature = simon;5, thì bạn phải thực hiện ép diễn viên để đưa nó trở lại một Cat simon = new Cat(); Animal creature = simon;4 hoặc một Cat simon = new Cat(); Animal creature = simon;5. Nếu bạn không chắc như đinh liệu class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 59 là một Cat simon = new Cat(); Animal creature = simon;5 hay một class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 85 trong thời gian chạy, bạn hoàn toàn có thể kiểm tra nó với class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 86 trước khi thực hiện ép kiểu. Nếu bạn không kiểm tra và bạn truyền sai, khối mạng lưới hệ thống thời gian chạy sẽ đưa ra một lỗi class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 66 class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 67 class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 68 class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 5Như chúng tôi đã đề cập trước đó, việc ép kiểu hoàn toàn có thể ảnh hưởng đến việc lựa chọn những mục thời gian biên dịch, ví dụ như những biến và những phương thức quá tải, nhưng không ảnh hưởng đến việc lựa chọn những phương thức bị ghi đè. Hình 6-4 đã cho tất cả chúng ta biết sự khác lạ. Như được hiển thị trong nửa trên của sơ đồ, việc chuyển tham chiếu
class Animal float weight; ... void eat() ... ... class Mammal extends Animal // inherits weight int heartRate; ... // inherits eat() void breathe() ... 46 sang loại Cat simon = new Cat(); Animal creature = simon;4 (mở rộng nó) ảnh hưởng đến việc lựa chọn biến bóng mờ Cat simon = new Cat(); Animal creature = simon;2 bên trong nó. Tuy nhiên, như nửa dưới của sơ đồ chỉ ra, việc ép kiểu không ảnh hưởng đến việc lựa chọn phương thức bị ghi đè class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 82Hình 6-4. Đúc và lựa chọn những phương pháp và biến
Truyền trong Java là vấn đề mà những lập trình viên nỗ lực tránh. Điều này sẽ không riêng gì có chính bới nó chỉ ra một điểm yếu trong cách gõ tĩnh của mã, mà chính bới những phép truyền cũng hoàn toàn có thể đơn giản là tẻ nhạt khi sử dụng và làm cho mã khó đọc hơn. Thật rủi ro, rất nhiều mã được viết bằng Java trong quá khứ không còn lựa chọn nào khác ngoài việc nhờ vào ép kiểu để nó hoàn toàn có thể hoạt động và sinh hoạt giải trí với bất kỳ loại đối tượng nào mà người tiêu dùng yêu cầu. java5. 0 đã ra mắt một tính năng ngôn từ mới, generics, một phần để xử lý và xử lý vấn đề này. Generics được cho phép người tiêu dùng "gõ" mã Java cho một loại đối tượng rõ ràng, vô hiệu nhu yếu truyền trong nhiều tình huống. Chúng ta sẽ đề cập rõ ràng về khái quát trong Chương 8 và xem cách chúng giảm nhu yếu truyền trong hầu hết mã Java
Sử dụng Superclass Constructor
Trước đây khi tất cả chúng ta nói về những hàm tạo, tất cả chúng ta đã thảo luận về cách câu lệnh đặc biệt
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 94 gọi một hàm tạo bị quá tải khi nhập vào một hàm tạo khác. Tương tự, câu lệnh class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 95 gọi hàm tạo của một lớp cha một cách rõ ràng. Tất nhiên, tất cả chúng ta đã và đang nói về cách Java thực hiện một chuỗi lệnh gọi hàm tạo gồm có hàm tạo của siêu lớp, vậy tại sao lại sử dụng rõ ràng class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 95? . Nếu tất cả chúng ta muốn gọi một hàm tạo của lớp bậc trên nhận những đối số, tất cả chúng ta phải thực hiện điều đó một cách rõ ràng bằng phương pháp sử dụng class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 95Nếu tất cả chúng ta định gọi một hàm tạo của lớp bậc trên với
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 95, thì đó phải là câu lệnh đầu tiên của hàm tạo của tất cả chúng ta, in như class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 94 phải là lệnh gọi đầu tiên tất cả chúng ta thực hiện trong một hàm tạo quá tải. Đây là một ví dụ đơn giản class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 6Trong ví dụ này, chúng tôi sử dụng
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 95 để tận dụng lợi thế của việc triển khai hàm tạo của lớp cha và tránh sao chép mã để thiết lập đối tượng nhờ vào tên của nó. Trên thực tế, vì lớp Cat simon = new Cat(); Animal creature = simon;01 không định nghĩa hàm tạo mặc định (không còn đối số), nên chúng tôi không còn lựa chọn nào khác ngoài việc gọi class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 95 một cách rõ ràng. Nếu không, trình biên dịch sẽ phàn nàn rằng nó không thể tìm thấy hàm tạo mặc định thích hợp để gọi. Nói cách khác, nếu bạn phân lớp một lớp có tất cả những hàm tạo đều nhận đối số, thì bạn phải gọi một trong những hàm tạo của lớp cha một cách rõ ràng từ ít nhất một trong những hàm tạo của lớp con của bạnCác biến thể hiện của lớp được khởi tạo khi trả về từ hàm tạo của lớp bậc trên, mặc dầu đó là vì lệnh gọi rõ ràng tới
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 95 hay lệnh gọi ẩn tới hàm tạo mặc định của lớp bậc trêntiết lộ đầy đủ. Constructor và khởi tạo
Bây giờ tất cả chúng ta hoàn toàn có thể kể toàn bộ câu truyện về cách những hàm tạo được link với nhau và khi khởi tạo biến thể hiện xảy ra. Quy tắc có ba phần và được áp dụng lặp lại cho từng hàm tạo liên tục được gọi
Nếu câu lệnh đầu tiên của hàm tạo là một câu lệnh thông thường—nghĩa là không phải lệnh gọi tới
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 94 hoặc class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 95—Java sẽ chèn một lệnh gọi ngầm định tới class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 95 để gọi hàm tạo mặc định của siêu lớp. Khi trở về từ lệnh gọi đó, Java khởi tạo những biến thể hiện của lớp hiện tại và tiến hành thực thi những câu lệnh của hàm tạo hiện tạiNếu câu lệnh đầu tiên của hàm tạo là lời gọi hàm tạo của lớp bậc trên thông qua
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 95, Java sẽ gọi hàm tạo của lớp bậc trên đã chọn. Khi trả về, Java khởi tạo những biến thể hiện của lớp hiện tại và tiếp tục với những câu lệnh của hàm tạo hiện tạiNếu câu lệnh đầu tiên của một hàm tạo là một lệnh gọi đến một hàm tạo bị quá tải thông qua
class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 94, thì Java sẽ gọi hàm tạo đã chọn và khi trả về, chỉ việc tiếp tục với những câu lệnh của hàm tạo hiện tại. Cuộc gọi đến hàm tạo của lớp cha đã xảy ra trong hàm tạo bị quá tải, rõ ràng hoặc ngầm định, vì vậy việc khởi tạo những biến thể hiện đã xảy raCác phương thức và lớp trừu tượng
Một phương thức trong Java hoàn toàn có thể được khai báo bằng công cụ sửa đổi
Cat simon = new Cat(); Animal creature = simon;09 để chỉ ra rằng nó chỉ là một nguyên mẫu. Một phương thức trừu tượng không còn phần thân; . Bạn không thể trực tiếp sử dụng một lớp có chứa một phương thức trừu tượng; class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 7Trong Java, một lớp chứa một hoặc nhiều phương thức trừu tượng phải được khai báo rõ ràng là một lớp trừu tượng, đồng thời sử dụng công cụ sửa đổi
Cat simon = new Cat(); Animal creature = simon;09 class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 8Một lớp trừu tượng hoàn toàn có thể chứa những phương thức phi trừu tượng khác và những khai báo biến thông thường, nhưng nó không thể được khởi tạo. Để được sử dụng, nó phải được phân lớp và những phương thức trừu tượng của nó phải được "ghi đè" bằng những phương thức triển khai phần thân. Không phải tất cả những phương thức trừu tượng đều phải được triển khai trong một lớp con duy nhất, nhưng một lớp con không ghi đè tất cả những phương thức trừu tượng của lớp cha của nó bằng những triển khai rõ ràng, thực tế cũng phải được khai báo
Cat simon = new Cat(); Animal creature = simon;09 class Cat extends Mammal // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() ... 9Các lớp trừu tượng đáp ứng một khung cho những lớp sẽ được “điền vào” bởi người triển khai. Ví dụ, lớp
Cat simon = new Cat(); Animal creature = simon;12 có một phương thức trừu tượng duy nhất mang tên là Cat simon = new Cat(); Animal creature = simon;13. Các lớp con rất khác nhau của Cat simon = new Cat(); Animal creature = simon;14 triển khai Cat simon = new Cat(); Animal creature = simon;13 theo cách riêng của chúng để đọc từ những nguồn riêng của chúng. Tuy nhiên, phần còn sót lại của lớp Cat simon = new Cat(); Animal creature = simon;14 đáp ứng hiệu suất cao mở rộng được xây dựng trên phương thức Cat simon = new Cat(); Animal creature = simon;13 đơn giản. Lớp con của Cat simon = new Cat(); Animal creature = simon;14 thừa kế những phương thức phi trừu tượng này để đáp ứng hiệu suất cao nhờ vào phương thức Cat simon = new Cat(); Animal creature = simon;13 đơn giản mà lớp con thực hiện
Post a Comment