Kotlin を勉強中なので、自分用まとめ
クラス
クラスの定義とインスタンス化
class MyClass {
private var str = "aaa"
var num = 1
fun showData () {
println("Str = ${str}, Num = ${num}")
}
}
val sample = MyClass()
sample.showData()
アクセス修飾子
| 修飾子 | 説明 |
|---|---|
| public | 全てのクラスからアクセス可能 |
| protected | クラスとサブクラス内からアクセス可能 |
| internal | 同じモジュール内のクラスからアクセス可能 |
| private | クラス内からのみアクセス可能 |
プロパティ
Kotlin ではフィールド(クラス内変数)が使えないが、代わりにプロパティが使える
- プロパティ
- アクセサー(getter/setter)を持つ
- getter / setter の記述は省略可能
- getter / setter を省略した場合、単純な値の get / set が提供される
プロパティの定義
var プロパティ名: 型 = 初期値
getter 関数
setter 関数
class MyClass {
var num = 1
set(value) { // 引数は value が使われる
if (value < 0) {
println("Illegal Value")
} else {
field = value
}
}
}
fun main() {
val sample = MyClass()
sample.num = -2 //=> Illegal Value
sample.num = 5
println(sample.num) //=> 5
}
コンストラクタ
プライマリコンストラクタ
クラスに一つだけ記述されるコンストラクタ
class MyClass constructor(str: String, num: Int) {
var str: String
var num: Int
init {
this.str = str // プロパティと引数が同じ名前のときは this を付けて差別化する
this.num = num
}
fun showData () {
println("Str = ${str}, Num = ${num}")
}
}
val sample = MyClass("abc", 3)
sample.showData() //=> Str = abc, Num = 3
プライマリコンストラクタのキーワードは省略可能
class MyClass (str: String, num: Int) {}
var / val を付けると、宣言と初期化を同時に行える
class MyClass (var str: String, var num: Int) {
fun showData () {
println("Str = ${str}, Num = ${num}")
}
}
セカンダリコンストラクタ
ひとつのクラスに2つ以上のコンストラクタを定義
初期化の処理を分岐させるような場合に使用される
class MyClass constructor(var str: String, var num: Int) {
constructor(str: String):this(str, 1) {}
constructor():this("xyz") {}
fun showData () {
println("Str = ${str}, Num = ${num}")
}
}
val sample1 = MyClass("abc", 3)
val sample2 = MyClass("aaa")
val sample3 = MyClass()
sample1.showData() //=> Str = abc, Num = 3
sample2.showData() //=> Str = aaa, Num = 1
sample3.showData() //=> Str = xyz, Num = 1
継承
継承元のクラス、メソッドには、open 修飾子が必要
open class BaseClass(var a: Int) {
open fun showData(){
println(this.a)
}
}
class MyClass(a: Int, var b: String) :BaseClass(a)
val instance = MyClass(1, "abc")
instance.showData() //=> 1
オーバーライド
override 修飾子をつけることで、継承元のメソッドを上書きする
open class BaseClass(var a: Int) {
open fun showData(){
println(this.a)
}
}
class MyClass(a: Int, var b: String) :BaseClass(a) {
override fun showData(){
println("${this.b}")
super.showData() // 継承元のメソッドを呼び出す
}
}
val instance = MyClass(1, "abc")
instance.showData() //=> abc, 1
抽象クラス
abstract 修飾子を付けることで、抽象クラス・メソッドになる
抽象メソッドは、実装部分を持つことはできない
abstract class AbstClass(var a: Int) {
abstract fun showData()
}
class MyClass(a: Int, var b: String) :AbstClass(a) {
override fun showData(){
println("${this.b}, ${this.a}")
}
}
val instance = MyClass(1, "abc")
instance.showData()
データクラス
データを保持するだけで、処理を持たないクラス
data class MyClass(val a: Int, val b: String)
データクラスの条件
- 一つ以上の引数を持つ
- 引数にはすべて
varかvalを付与 -
abstractopensealedinner修飾子は付けられない
データクラスにはいくつかのメソッドが用意されている
equals メソッド
同値性を確認する
data class MyClass(var a: String = ""){
var b: Int = 0
}
val m1 = MyClass("abc")
m1.b = 1
val m2 = MyClass("abc")
m2.b = 2
println(m1 == m2) //=> true (== で equals メソッドが呼ばれる)
toString メソッド
データクラスのオブジェクトを文字列化
println 関数を実行時に暗黙で呼ばれる
componentN
プロパティの値を個々の変数に分解する
val t = Triple("a", "b", 10)
println(t.component1()) //=> a
println(t.component2()) //=> b
println(t.component3()) //=> 10
分割代入で使用されている
val t = Triple("a", "b", 10)
val (x, y, z) = t
println(x) //=> a
println(y) //=> b
println(z) //=> 10
copy
オブジェクトのコピー
data class MyClass(val x: String, val y: String, val z: Int)
val m1 = MyClass("a", "b", 1)
val m2 = m1.copy(x = "c")
println(m2) //=> MyClass(x=c, y=b, z=1)
オブジェクト式
再利用しないクラス
object {クラス本体}
object: 基底クラス or インターフェイス {クラス本体}
Android 開発において、ボタンクリック時の処理を定義するときなどに使用できる
btn.setOnClickListener の引数はクラスである必要があるが、通常は他のボタンでは再利用しないので、オブジェクト式が使える
btn.setOnClickListener(object: View.OnClickListener {
override fun onClick(view: View) {
// ボタンクリック時の処理
}
})
SAM(Single Abstract Method)インターフェース
- 抽象メソッドをひとつだけ持つインターフェース
- ラムダ式で置き換えられる
// 上プログラムをラムダ式で置き換えたもの
btn.setOnClickListener{ クリックされた時の処理 }
オブジェクト宣言
ひとつのインスタンスしか持たないクラス
object オブジェクト名 {オブジェクト本体}
object MyObject {
val x = "a"
var y = 10
fun showData(){
println("${x}, ${y}")
}
}
MyObject.y = 20
MyObject.showData() //=> a, 20
ジェネリック型
データ型に依存しない、汎用的なコード記述
class MyClass<T>(var value:T) {
fun getVal(): T {
return value
}
}
val m1 = MyClass<String>("aaa")
val m2 = MyClass<Int>(10)
println(m1.getVal()) //=> aaa
println(m2.getVal()) //=> 10
m1.value = 1 // Error
ジェネリック関数
関数の呼び出し時に引数と戻り値の型を決める
fun <T> myFunction(arr: Array<T>): T = arr[arr.size - 1]
val a1 = arrayOf(1, 2, 3)
val a2 = arrayOf("a", "b", "c")
println(myFunction<Int>(a1))
println(myFunction<String>(a2))
ネストクラス
クラスの中にクラスを定義することができる
クラスA内で定義されたクラスBは、クラスA 内部からしか呼ぶことができない
class MyClassA{
private class MyClassB{
fun show () = println("class B")
}
fun run() {
val instB = MyClassB()
instB.show()
}
}
val instA = MyClassA()
instA.run() //=> class B