Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ohtsuchi/1df68f9e5780b50e99a1a521bfb98ebd to your computer and use it in GitHub Desktop.
Save ohtsuchi/1df68f9e5780b50e99a1a521bfb98ebd to your computer and use it in GitHub Desktop.
Kotlinスタートブック読書勉強会 第9章 補足

Kotlinスタートブック読書勉強会 第9章 補足


reference や他のサイトなどに記述があって、赤べこ本では割愛されている(または ver1.1 以降の)内容の引用 が中心

または 赤べこ本 第10章 以降 に掲載 されていて, 9章 のタイミングでついでに習った方が良さそうな内容


2. member の override

list 9.3 method の override

Functions and Lambdas - Functions - Function Usage - Default Arguments 参照

Overriding methods always use the same default parameter values as the base method.

[a] override した method は, 常にベースメソッドと同じ デフォルト値 を使用

When overriding a method with default parameters values, the default parameter values must be omitted from the signature:

[b] method を override した場合は, 引数の デフォルト値 は省略しなければいけない

open class A {
    open fun foo(x: Int = 10) = x + 1
    open fun foo2(x: Int = 20) = x + 2
    open fun foo3(x: Int) = x + 3
}

class B : A() {
    // 引数のデフォルト値は override元の定義(= 10) が使われる
    override fun foo(x: Int) = x - 1       // no default value allowed

    override fun foo2(x: Int = 20) = x - 2 // コンパイルエラー(An overriding function is not allowed to specify default values for its parameters)
    override fun foo3(x: Int = 30) = x - 3 // コンパイルエラー(An overriding function is not allowed to specify default values for its parameters)
}

fun main(args: Array<String>) {
    println(A().foo()) // 11
    println(B().foo()) // 9
}

Classes and Objects - Classes and Inheritance - Inheritance - Overriding Methods 参照

no open annotation on a function, ... same signature in a subclass is illegal

[1] open 付いていない function と同じシグニチャ を subclass で定義できない

In a final class (...), open members are prohibited.

[2] final class で open members は禁止(-> 警告)

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

    // 親class で `open` 付いていない method と同じ シグニチャ
    fun nv() {}           // コンパイルエラー('nv' hides member of supertype 'Base' and needs 'override' modifier)

    // `open` を付けていない class(`Derived`) の中で `open` を付けた member
    open fun nv2() {}     // 警告('open' has no effect in a final class)
}

A member marked override is itself open,

[3] override は それ自体が open (open override と指定しなくても 継承可能)

If you want to prohibit re-overriding, use final

[4] override の 再 override を禁止したければ final override にする

open class Base2 {
    open fun v2() {}
    open fun v3() {}
}
open class AnotherDerived() : Base2() {
    override fun v2() {}        // `override` is itself open
    final override fun v3() {}  // prohibit re-overriding, use `final`
}
class AnotherDerived2() : AnotherDerived() {
    override fun v2() {}
    override fun v3() {}  // コンパイルエラー('v3' in 'AnotherDerived' is final and cannot be overridden)
}

list 9.4 superclass の実装を使う

Classes and Objects - Classes and Inheritance - Inheritance - Calling the superclass implementation 参照

Inside an inner class, accessing the superclass of the outer class

inner class から outer class の 親class に アクセス

open class Foo {
    open fun f() { println("Foo.f()") }
}

class Bar : Foo() {
    override fun f() { println("Bar.f()") }
    fun f2() { println("Bar.f2()") }

    inner class Baz {
        fun f2() { println("Baz.f2()") }

        fun g() {
            super@Bar.f()         // Foo.f() (`super@Outer` 指定)
//          super.f()             // コンパイルエラー (Unresolved reference: f)
        }

        // inner class -> outer class へのアクセス (内部クラス は 外部クラス への参照を保持する)
        fun g2() {
            f()                   // Bar.f()

            // inner, outer class 両方に定義がある場合:
            f2()                  // Baz.f2()
            this@Bar.f2()         // Bar.f2() (`this@Outer` 指定)
        }
    }
}

fun main(args: Array<String>) {
    Bar().Baz().g()
    println("")
    Bar().Baz().g2()
}
  • 実行結果
Foo.f()

Bar.f()
Baz.f2()
Bar.f2()

list 9.5 property の override

Classes and Objects - Classes and Inheritance - Inheritance - Overriding Properties 参照

You can also override a val property with a var property, but not vice versa

valvar で override できる

interface Foo {
    val count: Int
}
class Bar2 : Foo {
    override var count: Int = 0  // val -> var の override は ok
}
  • var -> val の override は できない
interface Foo2 {
    var count: Int
}
class Bar3 : Foo2 {
    override val count: Int = 0  // var -> val の override は NG
    // Var-property public open val count: Int defined in Bar3 cannot be overridden by val-property public abstract var count: Int defined in Foo2
}

日本語訳 の訳(「その逆もまた然り」) 注意


6. visibility (可視性)

6.1 Package

  • java の場合
    • package の階層 と フォルダの階層(class ファイルの場所) を合わせる必要あり
  • kotlin の場合
    • フォルダの階層 と合わせなくても コンパイル通る

Basics - Packages and Imports 参照

If the package is not specified, ... belong to "default" package that has no name.

package 名を省略すると, "default" package (名前無し) に属する


6.3 class level における visibility modifier (可視性修飾子)

  • protected の 公開範囲 が java と異なるので注意

表 9.3

修飾子 Kotlin Java
public どこからでも (デフォルト) どこからでも
internal 同一 module 内のみ -
private 同一 class 内のみ
[inner class の 変数] 参照できない
同一 class 内のみ
[inner class の 変数] 参照できる
protected 同一 class 内 + subclass 内 のみ
[inner class の 変数] 参照できない
同一 class 内 + subclass 内 + 同一 package 内 のみ
[inner class の 変数] 参照できる

java の仕様は 【解決Java】アクセス修飾子(protected、privateなど) などを参照

Test01.java

package chap09;

public class Test01 {
    protected String prot = "protected";
}

Test02.java

package chap09;

public class Test02 {
    public String m() {
        return new Test01().prot; // 同一 package 内から アクセス可能
    }

    public static void main(String[] args) {
        System.out.println(new Test02().m()); // protected
    }
}

Convert Java File to Kotlin File してみると ...

protected -> public(デフォルト) に変換される

Test01.kt

package chap09

class Test01 {
    var prot = "protected"  // `protected` -> public(デフォルト) に変換
}

Test02.kt

package chap09

class Test02 {
    fun m(): String {
        return Test01().prot
    }

    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            println(Test02().m()) // protected
        }
    }
}

Classes and Objects - Visibility Modifiers - Classes and Interfaces 参照

NOTE for Java users: outer class does not see private members of its inner classes in Kotlin.

outer class から inner classes の private が見えない. (protected も同様)

class Outer {
    inner class Inner() {
        fun a() = 1            // public
        protected fun b() = 2  // protected
        private fun c() = 3    // private
    }
    val a = Inner().a()
    val b = Inner().b() // コンパイルエラー(Cannot access 'b': it is protected in 'Inner')
    val c = Inner().c() // コンパイルエラー(Cannot access 'c': it is private in 'Inner')
}

java は コンパイルエラーにならない

package chap09;

public class Outer {
    public class Inner {
        public final int a = 0;
        protected final int b = 0;
        private final int c = 0;
    }
    public final int a = new Inner().a;
    public final int b = new Inner().b;
    public final int c = new Inner().c;
}

Convert Java File to Kotlin File してみると ...

コンパイルエラー の状態で .kt に変換される

package chap09

class Outer {
    inner class Inner {
        val a = 0
        val b = 0         // `protected` -> `public`
        private val c = 0
    }

    val a = Inner().a
    val b = Inner().b
    val c = Inner().c     // コンパイルエラー(Cannot access 'c': it is private in 'Inner')
}

object declaration, companion object

  • ↑ で inner class の話が出たので, ついでに 「 class 内の object 」 も予習.
  • object declaration, companion object
  • シングルトンオブジェクト
  • コンストラクタ無し
  • interface 実装可能
  • 外側の class の インスタンス に対して private, protected メンバ にアクセス可能
    • factory method に最適
    • Kotlinイン・アクション 第4章 4.4.2 リスト 4.26 では (-> ソース 4.4/2_2)
      • 「 class の constructor を private に して(class User private constructor(val 中略...))
      • その class の factory method を companion object に定義 」する例が出てくる

コンパニオンオブジェクトの例(C.D). 比較のために普通の object も記述(A.B).

interface I1; interface I2; interface I3; interface I4;

class A() : I1 {
    val a1 = "a1"
    private var a_priv = "a_priv"
    protected var a_prot = "a_prot"

    // `object declaration`
    //   シングルトン. コンストラクタ無し.
    object B : I2 {
        val b1 = "b1"   // (状態は持てるが シングルトン なので注意)
        // val b2 = a1  // コンパイルエラー ( Unresolved reference: a1 )

        // 外側の class の インスタンス に対して private, protected メンバ にアクセス可能
        fun b3(): A = A().apply { a_priv = "a"; a_prot = "aa" }
        fun b4(a: A) = a.a_priv + a.a_prot
    }
}

class C() : I3 {
    val c1 = "c1"
    private var c_priv = "c_priv"
    protected var c_prot = "c_prot"

    // `object declaration`
    //   シングルトン. コンストラクタ無し.
    // `companion object`
    //   オブジェクト名 を 省略 した場合: `Companion`
    companion object D : I4 {
        val d1 = "d1"   // (状態は持てるが シングルトン なので注意)
        // val d2 = c1  // コンパイルエラー ( Unresolved reference: c1 )

        // 外側の class の インスタンス に対して private, protected メンバ にアクセス可能
        fun d3(): C = C().apply { c_priv = "c"; c_prot = "cc" }
        fun d4(c: C) = c.c_priv + c.c_prot
    }
}

fun p(a: Any) = println("${a::class.qualifiedName}")

fun main(args: Array<String>) {
    p(A())    // A 型
//  p(A)      // コンパイルエラー ( Classifier 'A' does not have a companion object, and thus must be initialized here )
//  p(A.B())  // コンパイルエラー ( Expression 'B' of type 'A.B' cannot be invoked as a function. The function 'invoke()' is not found )
    p(A.B)    // A.B 型

    val i1: I1 = A()
    val i2: I2 = A.B
    println(A.B.b1) // b1

    println("-------")

    p(C())    // C 型
    p(C)      // C.D 型  // (★注目★)
//  p(C.D())  // コンパイルエラー ( Expression 'D' of type 'C.D' cannot be invoked as a function. The function 'invoke()' is not found )
    p(C.D)    // C.D 型

    val i31: I3 = C()
    val i41: I4 = C.D
    val i42: I4 = C // (★注目★)
    println(C.D.d1) // d1
    println(C.d1)   // d1 (★Java の static メソッド 呼び出し と同じ構文★)
    println(C === C.D) // true
}
  • C = C.D となる
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment