Kế thừa Kotlin (Có ví dụ)

Trong bài viết này, bạn sẽ tìm hiểu về thừa kế. Cụ thể hơn, kế thừa là gì và cách triển khai nó trong Kotlin (với sự trợ giúp của các ví dụ).

Kế thừa là một trong những đặc điểm chính của lập trình hướng đối tượng. Nó cho phép người dùng tạo một lớp mới (lớp dẫn xuất) từ một lớp hiện có (lớp cơ sở).

Lớp dẫn xuất kế thừa tất cả các tính năng từ lớp cơ sở và có thể có các tính năng bổ sung của riêng nó.

Trước khi đi vào chi tiết về kế thừa Kotlin, chúng tôi khuyên bạn nên xem hai bài viết sau:

  • Lớp và đối tượng Kotlin
  • Kotlin Primary Constructor

Tại sao phải thừa kế?

Giả sử, trong ứng dụng của bạn, bạn muốn có ba nhân vật - một giáo viên dạy toán , một cầu thủ bóng đá và một doanh nhân .

Vì tất cả các nhân vật đều là người, họ có thể đi bộ và nói chuyện. Tuy nhiên, họ cũng có một số kỹ năng đặc biệt. Một giáo viên dạy toán có thể dạy toán , một cầu thủ bóng đá có thể chơi bóng đá và một doanh nhân có thể điều hành một doanh nghiệp .

Bạn có thể tạo riêng lẻ ba lớp người có thể đi bộ, nói chuyện và thực hiện kỹ năng đặc biệt của họ.

Trong mỗi lớp, bạn sẽ sao chép cùng một mã để đi bộ và nói chuyện cho mỗi nhân vật.

Nếu bạn muốn thêm một tính năng mới - ăn, bạn cần phải thực hiện cùng một mã cho mỗi nhân vật. Điều này có thể dễ dàng trở thành lỗi dễ xảy ra (khi sao chép) và mã trùng lặp.

Sẽ dễ dàng hơn rất nhiều nếu chúng ta có một Personlớp học với các tính năng cơ bản như nói chuyện, đi bộ, ăn, ngủ và thêm các kỹ năng đặc biệt vào các tính năng đó theo nhân vật của chúng ta. Điều này được thực hiện bằng cách sử dụng kế thừa.

Sử dụng thừa kế, bây giờ bạn không thực hiện cùng mã cho walk(), talk()eat()cho mỗi lớp. Bạn chỉ cần kế thừa chúng.

Vì vậy, đối với MathTeacher(lớp dẫn xuất), bạn kế thừa tất cả các tính năng của một Person(lớp cơ sở) và thêm một tính năng mới teachMath(). Tương tự như vậy, đối với Footballerlớp, bạn kế thừa tất cả các tính năng của Personlớp và thêm một tính năng mới playFootball(), v.v.

Điều này làm cho mã của bạn sạch hơn, dễ hiểu và có thể mở rộng.

Điều quan trọng cần nhớ là: Khi làm việc với kế thừa, mỗi lớp dẫn xuất phải thỏa mãn điều kiện cho dù nó "có phải là" lớp cơ sở hay không. Trong ví dụ trên, MathTeacher là a Person , Footballer là a Person . Bạn không thể có một cái gì đó như, Businessman là một Business .

Kế thừa Kotlin

Hãy cố gắng triển khai thảo luận ở trên trong mã:

 mở lớp Person (age: Int) (// mã cho ăn, nói, đi bộ) lớp MathTeacher (age: Int): Person (age) (// các tính năng khác của giáo viên toán) class Footballer (age: Int): Person ( age) (// các tính năng khác của cầu thủ) class Doanh nhân (tuổi: Int): Người (tuổi) (// các tính năng khác của doanh nhân)

Dưới đây, Personlà một lớp cơ sở, và các lớp học MathTeacher, FootballerBusinessmancó nguồn gốc từ lớp Person.

Lưu ý, từ khóa opentrước lớp cơ sở , Person. Nó quan trọng.

Theo mặc định, các lớp trong Kotlin là cuối cùng. Nếu bạn đã quen thuộc với Java, bạn biết rằng một lớp cuối cùng không thể được phân lớp. Bằng cách sử dụng chú thích mở trên một lớp, trình biên dịch cho phép bạn lấy các lớp mới từ nó.

Ví dụ: Kế thừa Kotlin

 open class Person(age: Int, name: String) ( init ( println("My name is $name.") println("My age is $age") ) ) class MathTeacher(age: Int, name: String): Person(age, name) ( fun teachMaths() ( println("I teach in primary school.") ) ) class Footballer(age: Int, name: String): Person(age, name) ( fun playFootball() ( println("I play for LA Galaxy.") ) ) fun main(args: Array) ( val t1 = MathTeacher(25, "Jack") t1.teachMaths() println() val f1 = Footballer(29, "Christiano") f1.playFootball() )

Khi bạn chạy chương trình, đầu ra sẽ là:

Tên tôi là Jack. Tuổi tôi 25 tôi dạy tiểu học. Tên tôi là Cristiano. Tôi 29 tuổi, tôi chơi cho LA Galaxy.

Ở đây, hai lớp MathTeacherFootballerđược dẫn xuất từ Personlớp.

Phương thức khởi tạo chính của Personlớp đã khai báo hai thuộc tính: tuổi và tên, và nó có một khối khởi tạo. Khối khởi tạo (và các hàm thành viên) của lớp cơ sở Personcó thể được truy cập bởi các đối tượng của các lớp dẫn xuất ( MathTeacherFootballer).

Các lớp có nguồn gốc MathTeacherFootballercó các chức năng thành viên của riêng chúng teachMaths()playFootball()tương ứng. Các hàm này chỉ có thể truy cập được từ các đối tượng của lớp tương ứng.

Khi đối tượng t1 của MathTeacherlớp được tạo,

 val t1 = MathTeacher (25, "Jack")

Các tham số được chuyển cho hàm tạo chính. Trong Kotlin, initkhối được gọi khi đối tượng được tạo. Vì, MathTeachercó nguồn gốc từ Personlớp, nó tìm kiếm khối khởi tạo trong lớp cơ sở (Người) và thực thi nó. Nếu MathTeachercó khối init, trình biên dịch cũng sẽ thực thi khối init của lớp dẫn xuất.

Tiếp theo, teachMaths()hàm cho đối tượng t1được gọi là t1.teachMaths()câu lệnh using .

Chương trình hoạt động tương tự khi đối tượng f1của Footballerlớp được tạo. Nó thực thi khối init của lớp cơ sở. Sau đó, playFootball()phương thức của Footballerlớp được gọi là using statement f1.playFootball().

Ghi chú quan trọng: Kế thừa Kotlin

  • Nếu lớp có một hàm tạo chính, thì cơ sở phải được khởi tạo bằng cách sử dụng các tham số của hàm tạo chính. Trong chương trình trên, cả hai lớp dẫn xuất đều có hai tham số agenamevà cả hai tham số này đều được khởi tạo trong hàm tạo chính trong lớp cơ sở.
    Đây là một ví dụ khác:
     open class Person(age: Int, name: String) ( // some code ) class Footballer(age: Int, name: String, club: String): Person(age, name) ( init ( println("Football player $name of age $age and plays for $club.") ) fun playFootball() ( println("I am playing football.") ) ) fun main(args: Array) ( val f1 = Footballer(29, "Cristiano", "LA Galaxy") )  
    Ở đây hàm tạo chính của lớp dẫn xuất có 3 tham số và lớp cơ sở có 2 tham số. Lưu ý rằng, cả hai tham số của lớp cơ sở đều được khởi tạo.
  • Trong trường hợp không có hàm tạo chính, mỗi lớp cơ sở phải khởi tạo cơ sở (sử dụng từ khóa super), hoặc ủy quyền cho một hàm tạo khác thực hiện điều đó. Ví dụ,
     fun main(args: Array) ( val p1 = AuthLog("Bad Password") ) open class Log ( var data: String = "" var numberOfData = 0 constructor(_data: String) ( ) constructor(_data: String, _numberOfData: Int) ( data = _data numberOfData = _numberOfData println("$data: $numberOfData times") ) ) class AuthLog: Log ( constructor(_data: String): this("From AuthLog -> + $_data", 10) ( ) constructor(_data: String, _numberOfData: Int): super(_data, _numberOfData) ( ) )
    Để tìm hiểu thêm về cách hoạt động của chương trình này, hãy truy cập Kotlin Secondary Constructor.

Ghi đè các chức năng và thuộc tính thành viên

If the base class and the derived class contains a member function (or property) with the same name, you can need to override the member function of the derived class using override keyword, and use open keyword for the member function of the base class.

Example: Overriding Member Function

 // Empty primary constructor open class Person() ( open fun displayAge(age: Int) ( println("My age is $age.") ) ) class Girl: Person() ( override fun displayAge(age: Int) ( println("My fake age is $(age - 5).") ) ) fun main(args: Array) ( val girl = Girl() girl.displayAge(31) )

When you run the program, the output will be:

 My fake age is 26.

Here, girl.displayAge(31) calls the displayAge() method of the derived class Girl.

You can override property of the base class in similar way.

Visit how Kotlin getters and setters work in Kotlin before you check the example below.

 // Empty primary constructor open class Person() ( open var age: Int = 0 get() = field set(value) ( field = value ) ) class Girl: Person() ( override var age: Int = 0 get() = field set(value) ( field = value - 5 ) ) fun main(args: Array) ( val girl = Girl() girl.age = 31 println("My fake age is $(girl.age).") )

When you run the program, the output will be:

 My fake age is 26.

As you can see, we have used override and open keywords for age property in derived class and base class respectively.

Calling Members of Base Class from Derived Class

Bạn có thể gọi các hàm (và các thuộc tính truy cập) của lớp cơ sở từ một lớp dẫn xuất bằng cách sử dụng supertừ khóa. Đây là cách thực hiện:

 open class Person() ( open fun displayAge(age: Int) ( println("My actual age is $age.") ) ) class Girl: Person() ( override fun displayAge(age: Int) ( // calling function of base class super.displayAge(age) println("My fake age is $(age - 5).") ) ) fun main(args: Array) ( val girl = Girl() girl.displayAge(31) )

Khi bạn chạy chương trình, đầu ra sẽ là:

 Tuổi tôi là 31. Tuổi giả của tôi là 26.

thú vị bài viết...