- Kotlinスタートブック読書勉強会 #6 で本編の発表の後に LTした内容
- 第9章 の 写経
reference や他のサイトなどに記述があって、赤べこ本では割愛されている(または ver1.1 以降の)内容の引用 が中心
または 赤べこ本 第10章 以降 に掲載 されていて, 9章 のタイミングでついでに習った方が良さそうな内容
Functions and Lambdas - Functions - Function Usage - Default Arguments 参照
[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 参照
[1] open
付いていない function と同じシグニチャ を subclass で定義できない
[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)
}
[3] override
は それ自体が open
(open override
と指定しなくても 継承可能)
[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)
}
Classes and Objects - Classes and Inheritance - Inheritance - Calling the superclass implementation 参照
inner class から outer class の 親class に アクセス
- inner class
- -> 赤べこ本 第13章-6 ネストしたクラス (p199) 参照
- -> Kotlinイン・アクション 第4章 4.1.4 参照
super@Outer
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()
Classes and Objects - Classes and Inheritance - Inheritance - Overriding Properties 参照
val
を var
で 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
}
日本語訳 の訳(「その逆もまた然り」) 注意
- java の場合
- package の階層 と フォルダの階層(class ファイルの場所) を合わせる必要あり
- kotlin の場合
- フォルダの階層 と合わせなくても コンパイル通る
Basics - Packages and Imports 参照
package 名を省略すると, "default" package (名前無し) に属する
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 参照
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')
}
- ↑ で inner class の話が出たので, ついでに 「
class
内のobject
」 も予習. - object declaration, companion object
- -> 赤べこ本 第13章-8 オブジェクト宣言 (p202) 参照
- -> 赤べこ本 第13章-9 コンパニオンオブジェクト (p203) 参照
- -> Kotlinイン・アクション 第4章 4.4 参照
- シングルトンオブジェクト
- コンストラクタ無し
- 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
に定義 」する例が出てくる
- 「 class の constructor を private に して(
コンパニオンオブジェクトの例(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
となる