#継承
Anyは全てのクラスの親クラス。
JavaのObjectとは異なる。
class Example // Anyから暗黙の継承
Kotlinのクラスは全て「Any」というクラスを継承している。Kotlinのクラスは全て非Null型のため、Null許容型であるJavaのObjectのサブクラスとなることはできない。そのため、非Null型として定義されたAnyクラスがKotlinにおける全てのクラスのスーパークラスとなっている。
クラスヘッダ内のコロンの後に型を書くと、明示的に親クラスを宣言できる。
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)