Наследование является важной особенностью объектно-ориентированного языка программирования. Наследование классов в Kotlin позволяет наследовать функцию существующего класса (или базового, или родительского класса) новому классу (или производному классу, или дочернему классу).
Основной класс называется суперклассом (или родительским классом), а класс, который наследует суперкласс, называется подклассом (или дочерним классом). Подкласс содержит черты суперкласса, а также свои собственные.
Концепция наследования допускается, когда два или более класса имеют одинаковые свойства. Это позволяет повторно использовать код. Производный класс имеет только один базовый класс, но может иметь несколько интерфейсов, тогда как базовый класс может иметь один или несколько производных классов.
В Kotlin производный класс наследует базовый класс, используя: оператор в заголовке класса (после имени производного класса или конструктора)
open class Base(p: Int){
}
class Derived(p: Int) : Base(p){
}
Предположим, что у нас есть два разных класса «Programmer» и «Salesman», имеющие общие свойства «name», «age» и «salary», а также свои собственные отдельные функции doProgram() и fieldWork(). Функция наследования позволяет нам наследовать (Employee), содержащий общие функции.
open class Employee(name: String, age: Int, salary: Float) {
// code of employee
}
class Programmer(name: String, age: Int, salary: Float): Employee(name,age,salary) {
// code of programmer
}
class Salesman(name: String, age: Int, salary: Float): Employee(name,age,salary) {
// code of salesman
}
Все классы Kotlin имеют общий суперкласс Any. Это суперкласс по умолчанию для класса без явного указания супертипов.
Например, класс Example неявно наследуется от Any.
class Example
- Ключевое слово open
- Наследование полей от класса
- Наследование методов от класса Kotlin
- Пример наследования Kotlin
- Первичный конструктор в наследовании
- Вторичный конструктор
- Переопределение метода Kotlin
- Пример без переопределения
- Пример переопределения метода Kotlin
- Переопределение свойств класса Kotlin
- Реализация суперкласса Kotlin
- Реализация нескольких классов Kotlin
Ключевое слово open
Поскольку классы Kotlin по умолчанию являются окончательными, их нельзя просто наследовать. Мы используем ключевое слово open перед классом, чтобы наследовать класс и сделать его неокончательным.
Пример:
open class Example{
// I can now be extended!
}
Наследование полей от класса
Когда мы наследуем класс для получения класса в Котлин, наследуются все поля и функции. Мы можем использовать эти поля и функции в производном классе.
Пример:
open class Base{
val x = 10
}
class Derived: Base() {
fun foo() {
println("x is equal to " + x)
}
}
fun main(args: Array) {
val derived = Derived()
derived.foo()
}
Выход:
x is equal to 10
Наследование методов от класса Kotlin
open class Bird {
fun fly() {
println("flying...")
}
}
class Duck: Bird() {
fun swim() {
println("swimming...")
}
}
fun main(args: Array) {
val duck = Duck()
duck.fly()
duck.swim()
}
Выход:
flying... swimming...
Пример наследования Kotlin
Здесь мы объявляем класс Employee суперклассом, а Programmer и Salesman — их подклассами. Подклассы наследуют имя свойств, возраст и зарплату, а также подклассы содержат свои собственные функции, такие как doProgram() и fieldWork().
open class Employee(name: String, age: Int, salary: Float) {
init {
println("Name is $name.")
println("Age is $age")
println("Salary is $salary")
}
}
class Programmer(name: String, age: Int, salary: Float):Employee(name,age,salary){
fun doProgram() {
println("programming is my passion.")
}
}
class Salesman(name: String, age: Int, salary: Float):Employee(name,age,salary){
fun fieldWork() {
println("travelling is my hobby.")
}
}
fun main(args: Array){
val obj1 = Programmer("Ashu", 25, 40000f)
obj1.doProgram()
val obj2 = Salesman("Ajay", 24, 30000f)
obj2.fieldWork()
}
Выход:
Name is Ashu. Age is 25 Salary is 40000.0 programming is my passion. Name is Ajay. Age is 24 Salary is 30000.0 travelling is my hobby.
Первичный конструктор в наследовании
Если базовый и производный класс имеют первичный конструктор, в этом случае параметры инициализируются в первичном конструкторе базового класса. В приведенном выше примере наследования все классы содержат три параметра «имя», «возраст» и «зарплата», и все эти параметры инициализируются в первичном конструкторе базового класса.
Когда базовый и производный класс содержат разное количество параметров в своем основном конструкторе, тогда параметры базового класса инициализируются из объекта производного класса.
Пример:
open class Employee(name: String,salary: Float) {
init {
println("Name is $name.")
println("Salary is $salary")
}
}
class Programmer(name: String, dept: String, salary: Float):Employee(name,salary){
init {
println("Name $name of department $dept with salary $salary.")
}
fun doProgram() {
println("Programming is my passion.")
}
}
class Salesman(name: String, dept: String, salary: Float):Employee(name,salary){
init {
println("Name $name of department $dept with salary $salary.")
}
fun fieldWork() {
println("Travelling is my hobby.")
}
}
fun main(args: Array){
val obj1 = Programmer("Ashu", "Development", 40000f)
obj1.doProgram()
println()
val obj2 = Salesman("Ajay", "Marketing", 30000f)
obj2.fieldWork()
}
Выход:
Name is Ashu. Salary is 40000.0 Name Ashu of department Development with salary 40000.0. Programming is my passion. Name is Ajay. Salary is 30000.0 Name Ajay of department Marketing with salary 30000.0. Travelling is my hobby.
Когда создается объект производного класса, он сначала вызывает свой суперкласс и выполняет блок инициализации базового класса, а затем свой собственный.
Вторичный конструктор
Если производный класс не содержит первичного конструктора, то необходимо вызвать вторичный конструктор базового класса из производного класса с использованием ключевого слова super.
Например,
open class Patent {
constructor(name: String, id: Int) {
println("execute super constructor $name: $id")
}
}
class Child: Patent {
constructor(name: String, id: Int, dept: String): super(name, id) {
print("execute child class constructor with property $name, $id, $dept")
}
}
fun main(args: Array) {
val child = Child("Ashu",101, "Developer")
}
Выход:
execute super constructor Ashu: 101 execute child class constructor with property Ashu, 101, Developer
В приведенном выше примере, когда создается объект класса Child, он вызывает свой конструктор и инициализирует его параметры значениями «Ashu», «101» и «Developer». В то же время конструктор дочернего класса вызывает свой конструктор суперкласса, используя ключевое слово super со значениями имени и идентификатора. Из-за наличия ключевого слова super тело конструктора суперкласса выполняется первым и возвращается к конструктору дочернего класса.
Переопределение метода Kotlin
Переопределение метода означает предоставление конкретной реализации метода super (родительского) класса в его подкласс (дочерний класс).
Другими словами, когда подкласс переопределяет или изменяет метод своего суперкласса на подкласс, это называется переопределением метода. Переопределение метода возможно только при наследовании.
Правила переопределения методов в Kotlin:
- Родительский класс и его метод или свойство, которые должны быть переопределены, должны быть открытыми (неокончательными).
- Имя метода базового класса и производного класса должно совпадать.
- Метод должен иметь тот же параметр, что и в базовом классе.
Пример без переопределения
open class Bird {
open fun fly() {
println("Bird is flying...")
}
}
class Parrot: Bird() {
}
class Duck: Bird() {
}
fun main(args: Array) {
val p = Parrot()
p.fly()
val d = Duck()
d.fly()
}
Выход:
Bird is flying... Bird is flying...
В приведенном выше примере программы без переопределения метода базового класса мы обнаружили, что оба производных класса Parrot и Duck выполняют одну и ту же общую операцию. Чтобы решить эту проблему, мы используем концепцию переопределения метода.
Пример переопределения метода Kotlin
В этом примере метод fly() родительского класса Bird переопределяется в его подклассах Parrot и Duck. Чтобы переопределить метод родительского класса, родительский класс и его метод, который будет переопределен, должны быть объявлены как открытые. В то же время метод, который переопределяется в дочернем классе, должен предваряться ключевым словом override.
open class Bird {
open fun fly() {
println("Bird is flying...")
}
}
class Parrot: Bird() {
override fun fly() {
println("Parrot is flying...")
}
}
class Duck: Bird() {
override fun fly() {
println("Duck is flying...")
}
}
fun main(args: Array) {
val p = Parrot()
p.fly()
val d = Duck()
d.fly()
}
Выход:
Parrot is flying... Duck is flying...
Переопределение свойств класса Kotlin
Свойство суперкласса также может быть переопределено в его подклассе аналогично методу. Свойство цвета класса Bird переопределяется и модифицируется в его подклассах Parrot и Duck.
open class Bird {
open var color = "Black"
open fun fly() {
println("Bird is flying...")
}
}
class Parrot: Bird() {
override var color = "Green"
override fun fly() {
println("Parrot is flying...")
}
}
class Duck: Bird() {
override var color = "White"
override fun fly() {
println("Duck is flying...")
}
}
fun main(args: Array) {
val p = Parrot()
p.fly()
println(p.color)
val d = Duck()
d.fly()
println(d.color)
}
Выход:
Parrot is flying... Green Duck is flying... White
Мы можем переопределить свойство val свойством var в наследовании, но наоборот неверно.
Реализация суперкласса Kotlin
Производный класс также может вызывать методы и свойства своего суперкласса, используя ключевое слово super.
Например:
open class Bird {
open var color = "Black"
open fun fly() {
println("Bird is flying...")
}
}
class Parrot: Bird() {
override var color = "Green"
override fun fly() {
super.fly()
println("Parrot is flying...")
}
}
fun main(args: Array) {
val p = Parrot()
p.fly()
println(p.color)
}
Выход:
Bird is flying... Parrot is flying... Green
Реализация нескольких классов Kotlin
В Kotlin производный класс использует имя супертипа в угловых скобках, например, gsuper, когда он реализует одно и то же имя функции, предоставленное в нескольких классах.
Например, производный класс Parrotext является продолжением своего суперкласса Bird и реализует интерфейс Duck, содержащий ту же функцию fly(). Чтобы вызвать конкретный метод каждого класса и интерфейса, мы должны указать имя супертипа в угловых скобках как super.fly() и super.fly() для каждого метода.
open class Bird {
open var color = "Black"
open fun fly() {
println("Bird is flying...")
}
}
interface Duck {
fun fly() {
println("Duck is flying...")
}
}
class Parrot: Bird(),Duck {
override var color = "Green"
override fun fly() {
super.fly()
super.fly()
println("Parrot is flying...")
}
}
fun main(args: Array) {
val p = Parrot()
p.fly()
println(p.color)
}
Выход:
Bird is flying... Duck is flying... Parrot is flying...
