Kotlin Programming Intermediate - 7


次の5編では、クラスの継承、上書き、オーバーロードについて説明します.

クラス継承


継承


まず、継承は親に対して、子は親の特徴を継承します.
遺伝学の概念から見ると、親と子供は似ている.
したがって、以前のパブリケーションでは、Aという親がBという子クラスを継承すると、Aクラスにキーワードopenが追加された.
open class Base (var firstName:String="길동", var lastName:String="홍", var age:Int=24) {
//class Base {

    /*
    var firstName:String
    var lastName:String
    var age:Int

    constructor(firstName:String, lastName:String, age:Int) {
        this.firstName = firstName
        this.lastName = lastName
        this.age = age
    }
    */

    open val fullName:String
        get() = "$firstName $lastName"

}

class Child(firstName:String, lastName:String, age:Int, var address:String) : Base(firstName, lastName, age) {

    // 또는 var address:String

    override val fullName:String        // 오버라이딩하려면 오버리이드 받을 변수, 클래스, 메서드 모두 open이 들어가야 함.
        get() = "$firstName $age $address"
}
まず、5回目の位置決めでは、作成者はコメントセクションのようにメンバー変数を個別に宣言し、constructorで作成できますが、クラス名の横で宣言するだけでよいことに気づきました.
このうち、Childというクラスは、Baseというクラスを継承し、その文字列変数はChildであり、addressクラスにのみ属します.
したがって、Childクラスにaddressを構造関数として追加し、親Baseで受信した変数を宣言します.
次に、親のfullName変数を上書きしました.親は継承されているので、openを追加し、子は継承されているので、継承された変数にoverrideを追加しました.fullNameは単独の値ではなく、get()によって指定されたgetterである.
別の例を見てみましょう.
open class Bird(var name:String, var wing:Int, var color:String) {

    fun fly() = println("fly wing: $wing")

    override fun toString(): String {
        return "Bird(name='$name', wing=$wing, color='$color')"
    }

    open fun allData() = print("$name $wing $color ")


}
Birdに示すように、クラスは他のクラスに継承する親です.
コンストラクション関数には3つの変数があり、クラス内には2つのメンバーメソッドと上書きされたopenがあります.
このときtoStringというallDataがあるので,このメンバのメソッドは他のクラスが継承し,上書きすることができる.
したがって、2つのクラスは次のように継承されます.
class Lark(name:String, wing:Int, color:String) : Bird(name, wing, color) {
    fun singHitOne() = println("짹짹")
}

// 이렇게도 상속을 받을 수 있다.
class Parrot : Bird {

    var volume:Int

    constructor(name:String, wing:Int, color:String, volume:Int):super(name, wing, color) {
        this.volume = volume
    }

    override fun toString(): String {
        return super.toString() + "Parrot(volume=$volume)"
    }

    override fun allData() {
        super.allData()
        println("$volume")
    }

}
openはジェネレータをクラス名の横に宣言し、Larkはジェネレータをクラス内部のjava構文として宣言します.
ここで、ParrotクラスはParrotをコンストラクション関数として使用し、Javaではsuperが親クラスのコンストラクション関数を呼び出す.
すなわち、superは、親の作成者を継承して初期化する.
親のconstructor(name:String, wing:Int, color:String, volume:Int):super(name, wing, color)を上書きすることによって、親のallDataallDataとして呼び出され、追加のsuper値が出力される.

かふか


メソッドオーバーロードとは、名前を持つが異なるパラメータを持つ複数のメソッドを定義することです.
クラスに次のメソッドを宣言したとします.
class Calc {

    fun add(x:Int, y:Int):Int = x + y
    fun add(x:Double, y:Double):Double = x + y
    fun add(x:Int, y:Int, z:Int):Int = x + y + z
    fun add(x:Double, y:Double, z:Double):Double = x + y + z

}
関数名はvolumeであるが、パラメータとしての受信値は異なる.これを過負荷と呼ぶ.
次のようにメイン関数からオブジェクトとして作成できます.
fun main(args: Array<String>) {

	val calc = Calc()
    
	println(cal.add(3, 4))
	println(cal.add(3.12, 4.34))
	println(cal.add(3, 4, 5))
	println(cal.add(3.12, 4.34, 7.54))

}

抽象クラスとインタフェース


抽象クラス


抽象クラスは抽象クラスであり、通常のクラスと同様にメンバー変数を有してもよいし、メンバーメソッドを有してもよい.
しかしながら、唯一の違いは、従来の方法ではなく、方法で抽象的な方法を宣言しなければならないことである.すなわち、抽象的な方法は、値addを含まずにプロトタイプのみを宣言しなければならない.
簡単な例を挙げる.
abstract class Printer {
   abstract fun print()
   fun method() = println("Printer Method()")
}

class MyPrinter : Printer() {
    override fun print() {
        println("출력합니다!!")
    }
}
このように宣言すると、returnクラスは抽象クラスMyPrinterを継承し、抽象クラスのPrinterメソッドを上書きする.
さらに、抽象クラスはjavaのようにキーワードprintを記録しなければならない.
抽象クラスを継承するabstractクラスをオブジェクトとして作成します.
fun main(args: Array<String>) {

	val prt = MyPrinter()
	prt.print()

}
使用可能です.
さらに、抽象クラスは、通常のメソッドと抽象メソッドとして宣言することもできます.
abstract class Vehicle(val name:String, val color:String, val weight:Double) {

    abstract var maxSpeed:Double    // 추상 property

    var year:Int = 2019

    abstract fun start()            // 추상 method
    abstract fun stop()

    fun displaySpecs() {
        println("Name: $name, Color: $color, Weight: $weight, Year: $year, MaxSpeed: $maxSpeed")
    }

}
ここでのMyPrinterの方法は、上述したdisplaySpecsおよびstartの方法とは異なり、関数内部が指定されているため、抽象的な方法とは見なされず、従来の方法と見なすべきである.
抽象クラスには、通常のメソッド、抽象メソッド、メンバー変数、またはメンバー変数の値を指定できます.

トップレベルオブジェクトstop継承の使用


JAvaにはobjectというトップレベルのオブジェクトがあります.これにより、任意のオブジェクトにアクセスできます.
Cottinでもこの方法を使用できますが、変数に入れて直接メイン関数で使用することもできます.
抽象クラスObjectを作成し、変数Printerに保存します.
abstract class Printer {
    abstract fun print()
    fun method() = println("Printer Method()")
}

val myPrinter = object : Printer() {
    override fun print() {
        println("myPrinter print()")
    }

}
メイン関数でmyPrinterとして直接使用して、変数に継承して保存できます.
fun main(args: Array<String>) {

	myPrinter.print()

}

インタフェース


インタフェースは抽象的な方法とは異なる.
Javaのインタフェースには抽象的なメソッドしか含まれませんが、コトリンのインタフェースにはメンバー変数を持つことができます.
たとえば、次のインタフェースがあるとします.
interface Foo {
    var bar:Int
    fun method(str:String)
}
クラスとして実施する場合
class CreateFoo(val _bar:Int) : Foo {
    override var bar: Int = _bar

    override fun method(str: String) {
        println("$bar $str")
    }
}
この形状の内部変数objectと方法barはインタフェースから継承されているので,methodを追加した.

複数のインタフェースを継承


クラス間には複数の継承はできませんが、クラスは複数のインタフェースを継承できます.
interface Bird {
    var wings:Int
    fun fly()

    fun jump() {    // 메서드를 정의할 수 있다?
        println("Bird jump")
    }
}

interface Horse {
    var maxSpeed:Int
    fun run()

    fun jump() {    // 메서드를 정의할 수 있다?
        println("Horse jump & maxSpeed ")
    }
}
2つのインタフェースが準備されています.各インタフェースには変数と2つの方法があります.
2つのインタフェースを継承するoverrideクラスを作成しましょう.
class Pegasus : Bird, Horse {
    override var wings: Int = 2
    override var maxSpeed: Int = 100

    override fun fly() {
        println("Fly Sky~~")
    }

    override fun run() {
        println("Run~~")
    }

    override fun jump() {
        super<Bird>.jump()      // 그냥 jump를 호출하면 상속받는 인터페이스에 모두 jump가 있어서 에러가 발생하므로 제네릭 타입으로 상위 타입을 지정해주자!
        println("Pegasus Jump~~!!")
    }

}
すべての変数と方法はインタフェースから実装されるため、Pegasusを追加しました.
重要な事実は、2つのインタフェースに存在し、競合が繰り返される可能性があるoverrideと呼ばれる方法に注目する必要がある.
したがって、親タイプを指定する必要がありますが、jumpを追加してJENICとして指定し、superのメソッドを使用します.
メイン関数で使用する場合は、
fun main(args: Array<String>) {

    val pega = Pegasus()
    pega.fly()
    pega.run()
    pega.jump()

}
使用可能です.

過剰


overlightは、継承クラス(<Bird>)中継ベアリングクラス(Child)を再定義するための方法または変数にまとめられる.

...過剰な行動定義の実践を一度に理解する。


過剰な行動がどのように起こっているのかを理解するために、次のカテゴリを想定します.

まず、Parentというクラスと、Animalの継承インタフェースを持つPetCatのクラスを作成します.
次に、DogオブジェクトまたはCatオブジェクトをパラメータとして使用して、文を出力する方法を有するDogクラスを作成します.

継承するクラスとインタフェースの作成


まず、継承するクラスを作成します.
class Animal(val name:String) {}
メンバー変数と対応するコンストラクション関数が1つしかないため、このクラスを指定します.
このクラスは継承するクラスなので、前にMasterが加算されます.
open class Animal(val name:String) {}
次にインタフェースを作成します.
インタフェース内では、open変数とメッセージを作成し、categoryという文字列変数とメソッドgetterspeciesを作成します.feeding()で「Keeppatting」を出力できます.
interface Pet {
    var category:String
    val msgTags:String
        get() = "I love my pet!"

    var species:String
    fun feeding()
    fun patting() {
        println("Keep patting")
    }
}

継承クラスの作成

patting()pattingクラスは、CatインタフェースおよびDogクラスを継承する.
この場合、PetクラスからAnimalを取得する必要があります.さらに、Animalインタフェースで変数nameおよび方法Petを実装するので、追加のサポートを提供することができる.また、インタフェースのspeciesもコンストラクション関数であるため、コンストラクション関数で上書きする必要がある.
class Cat(name:String, override var category: String) : Pet, Animal(name) {

    override var species: String = "Cat"
    override fun feeding() {
        println("Feeding Cat")
        println("Cat Name: $name")
    }
}

class Dog(name:String, override var category: String) : Pet, Animal(name) {

    override var species: String = "Dog"
    override fun feeding() {
        println("Feeding Dog")
        println("Dog Name: $name")
    }
}

給電クラスの作成


オブジェクトとして作成されると、categoryクラスはパラメータとしてMasterまたはMasterクラスを受信し、各クラスに宣言されたCat変数の値を出力し、インタフェースのDogは各クラスの実装形態を表示する.
class Master {

    fun playWithPet(pet:Pet) {
        println(pet.species)
        pet.feeding()
    }
}
このクラスは、パラメータとしてspeciesというインタフェース形式で、feedingに割り当てられた値とPetメソッドを呼び出した結果を示す方法が内部にのみ存在する.
したがって、species関数において各オブジェクトが作成され、feedingオブジェクトの内部の方法においてmainおよびMasterオブジェクトがArgumentsとして実行される.
fun main(args: Array<String>) {

    val master = Master()
    val dog = Dog("바둑이", "Small")
    master.playWithPet(dog)

    val cat = Cat("야옹이", "Middle")
    master.playWithPet(cat)

}

結果は次のとおりです.