4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Kotlinの継承について

Last updated at Posted at 2019-08-22

#継承

Anyは全てのクラスの親クラス。
JavaのObjectとは異なる。

class Example // Anyから暗黙の継承

Kotlinのクラスは全て「Any」というクラスを継承している。Kotlinのクラスは全て非Null型のため、Null許容型であるJavaのObjectのサブクラスとなることはできない。そのため、非Null型として定義されたAnyクラスがKotlinにおける全てのクラスのスーパークラスとなっている。

※参考
基底はObjectクラスではなくAnyクラス

クラスヘッダ内のコロンの後に型を書くと、明示的に親クラスを宣言できる。

open class Base(p: Int)

class Derived(p: Int) : Base(p)

親クラスのコンストラクタが引数を持っているならば、子クラスのプライマリコンストラクタの引数を使って、親クラスのコンストラクタに渡すことができる。

もし子クラスがプライマリコンストラクタを持たない場合は、セカンダリコンストラクタでsuperキーワードを使って初期化しなければいけない。

class MyView : View {
    constructor(ctx: Context) : super(ctx) {
    }

    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) {
    }
}

クラスのopenアノテーションはJavaのfinalの反対で、継承を許可する。

#メンバのオーバーライド
クラスと同様メンバメソッドもopenをつけることで継承できるようになる。

open class Base {
  open fun v() {}
  fun nv() {}
}
class Derived() : Base() {
  override fun v() {}
}

openをつけないで、子クラスで同じメソッドを宣言しようとするとコンパイルエラーになる。
finalクラス(openをつけないクラス)では、メソッドにopenをつけることはできない。

overrideしたメソッドをfinalにして、それ以降はオーバーライドさせないようにすることもできる。

open class AnotherDerived() : Base() {
  final override fun v() {}
}

プロパティのオーバーライドもメソッドのオーバーライドと同じように宣言できる。

open class Foo {
    open val x: Int get { ... }
}

class Bar1(override val x: Int) : Foo() {

}

継承をする時に、valをvar、varをvalにすることができる。

#待って!じゃあどうやって自分のライブラリをハックすれば良いの?!
オーバライドのKotlinでの方法()には1つ問題がある。
あなたが使用しているライブラリ内の何かをサブクラス化し、いくつかのメソッドをオーバライドして(ライブラリの設計者はそれを意図していない) そこにいくつかの厄介なハックを導入するのが難しくなる、という問題。

次のような理由から、これは欠点ではないと考えられている。

ベストプラクティスは「とにかくこれらのハックを許可すべきではない」ということである
同様のアプローチを取っている他の言語 (C++, C#) はうまくいっている
もし本当にこのハックが必要ならば、それでも方法は残っている:いつでもハックをJavaで書き、Kotlinから呼ぶことができる( Java Interopを参照 してください )し、Aspectフレームワークはいつもこれらの目的にかなう

#ルールのオーバーライド
Kotlinの継承の実装ルールは以下。

open class A {
  open fun f() { print("A") }
  fun a() { print("a") }
}

interface B {
  fun f() { print("B") } // インタフェースのメンバはデフォルトで'open'
  fun b() { print("b") }
}

class C() : A(), B {
  // オーバーライドするためにコンパイラは f() を要求する
  override fun f() {
    super<A>.f() // A.f()の呼び出し
    super<B>.f() // B.f()の呼び出し
  }
}

f()については、両方の親クラス(インターフェース)で定義されているので
子クラスでは独自の定義をしなければならない。

#抽象クラス

クラスとそのメンバはabstractを使用して、抽象クラス・抽象メンバとして宣言することができる。
これらにopenアノテーションは不要。

open class Base {
  open fun f() {}
}

abstract class Derived : Base() {
  override abstract fun f()
}

#コンパニオンオブジェクト
Kotlinでは、JavaやC#とことなり、クラスはstaticメソッドを持たない。
ほとんどの場合、代替として、パッケージレベルの関数を使用することが推奨されている。

クラスインスタンスを持たずに呼べるがクラス内部(例えばファクトリメソッド)へのアクセスが要る関数を書く必要があればcompanion objectの中にメソッドを書ける。

class MyClass {
    companion object Factory {
        fun create(): MyClass = MyClass()
    }
}

val instance = MyClass.create() のように使える。

※参考
kotlinのcompanionとcompanion objectをちゃんとまとめる。

#シールクラス
※参考
[シールクラスで継承可能なクラスを制限する (sealed class)]
(https://maku77.github.io/kotlin/basic/sealed-class.html)

KotlinのSealed Classを使いこなす

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?