Help us understand the problem. What is going on with this article?

Kotlinの継承について

継承

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)

KotlinのSealed Classを使いこなす

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away