Kotlinでは全てはオブジェクトであり、Javaにあるようなプリミティブはありません。以下に挙げるような基本的な型もオブジェクトとして扱われます。ただし、これらの基本的な型はコンパイル時にプリミティブへと最適化されるため、パフォーマンスが犠牲になることはありません(総称型の型パラメータで使われている場合など、一部例外はある)。
Boolean型は真偽値を表し、値としてtrue
またはfalse
をとります。true
は真、false
は偽を表します。Boolean型の変数は、以下のように宣言します。
val boolean: Boolean = true
※ 説明のため明示的に型を記載していますが、実際にコードを書く際は、型推論を用いて適宜型の記載を省略してください。
以下のように、何らかの評価結果を直接代入することも可能です。括弧は省略しても問題ありません。
val boolean: Boolean = (a > 0)
真偽値の判定には!
を用います。not()
を用いても同様の結果を得ることができます。個人的には、not()
を使った方が可読性が高くて良いかな、と思います。
!boolean
boolean.not()
Kotlinでは、全ての数値型はNumberを親クラスに持ち、Number型で用意されている関数を使うことができます。また、数値型同士の暗黙的な型変換を行うことはできず、Number型で用意されているtoInt()
、toDouble()
などを用いて明示的に型変換を行います。
Kotlinで用意されている整数型は、Byte型、Short型、Int型、Long型があります。
型 | ビット数 | 最小値 | 最大値 |
---|---|---|---|
Byte | 8 | -128 | 127 |
Short | 16 | -32,768 | 32,767 |
Int | 32 | -2,147,483,648 | 2,147,483,647 |
Long | 64 | -9,223,372,036,854,775,808 | 9,223,372,036,854,775,807 |
これらの数値型の中で、基本となるのはInt型になると思います。もちろん、要件次第で他の型を使うのは問題ありません。
数値リテラルには、_
を用いて区切りを入れることができます。_
を用いて区切りを入れた場合、実際の数値には影響を与えません。
val int: Int = 1_000_000 // 1000000
Long型は、数値リテラルの後にL
を付けて表します。
val long: Long = 0L
Long型の変数は以下のように数値リテラルにL
を付けずに宣言することも可能ですが、Long型を使いたい時に誤ってInt型を使用しないよう、明示的にL
を付けた方が良いでしょう。
val long: Long = 0
Kotlinで用意されている浮動小数点型は、Float型とDouble型があります。整数を扱う整数型に対して、浮動小数点型は少数を扱います。
型 | ビット数 |
---|---|
Float | 32 |
Double | 64 |
Float型は、Long型の宣言と同様に、数値リテラルの後にf
またはF
を付けて表します。Long型と異なり、Float型は明示的にf
またはF
を付けなければなりません。
val float: Float = 0.0f
Char型は、単一の文字を表します。文字リテラルをシングルクオート'
で囲んで表します。
val char: Char = 'a'
String型は、文字列を表します。文字リテラルをダブルクオート"
で囲んで表します。
val string: String = "string"
Kotlinでは、null
となり得る変数とnull
となり得ない変数を区別して扱います。これにより、変数がnull
になり得るか、なり得ないかを型のレベルで区別して取り扱うことが可能です。ここでは、null
となり得る変数をnullableな変数、null
になり得ない変数をnon-nullな変数と呼びます。
nullableな変数を宣言するためには、型の名称の後ろに?
を付けて宣言します。以下のコードでは、nullableなString型の変数nullableString
を宣言しています。
var nullableString: String? = "string"
nullableString
には、String型の値の他に、null
を代入することが可能です。
nullableString = null
これに対して、non-nullな変数を宣言する場合は、型の名称の後ろに?
を付けずに変数を宣言します。
var nonNullString: String = "string"
また、non-nullな変数を宣言する場合には、型推論を用いることも可能です。
var nonNullString = "string"
non-nullな変数にnull
を代入することはできません。例えば、以下のコードはコンパイルエラーとなります。
nonNullString = null // コンパイルエラー
Kotlinでは、non-nullな変数にnullを代入することは許されていません。これにより、変数がnull
になり得るか、なり得ないかを型のレベルで識別することが可能です。
Kotlinでは、全てのnullableな型はAny?型を親クラスに持ちます。例えば、String?型はAny?型を親クラスに持ちます。
println(nullableString is Any?) // true
一方、Kotlinの全てのnon-nullな型は、Any型を親クラスに持ちます。例えば、String型はAny型を親クラスに持ちます。
println(nonNullString is Any) // true
さらに、Any型はAny?型を親クラスに持ちます。すなわち、Any?型の変数にAny型の値を代入することは可能ですが、逆にAny型の変数にAny?型の値を代入することはできません。
これは同時に、nullableな変数にnon-nullな値を代入することは可能ですが、non-nullな値にnullableな値を代入することはできない、ということを意味します。
このようにして、Kotlinではnullableな型とnon-nullな型を区別して取り扱い、null安全を実現しています。
クラス名の後の括弧内にプライマリコンストラクタに渡す引数を定義することができます。プライマリコンストラクタに引数を渡す必要がない場合は省略可能です。プライマリコンストラクタに渡した引数は、プロパティの宣言と初期化ブロックの中でアクセスすることが可能です。
class Person constructor(name: String) {
val name: String = name
}
以下の例では、初期化ブロックにおいてプライマリコンストラクタで渡された引数を出力した後、プロパティに代入しています。
class Person constructor(name: String) {
val name: String
init {
println("set name as $name")
this.name = name
}
}
プライマリコンストラクタに渡された引数をそのままプロパティとして宣言することも可能です。この場合、引数名の前にアクセス修飾子とval
キーワードまたはvar
キーワードを与えます。この表記には、プロパティの宣言と代入を一箇所で完結できるためコードが簡潔になるという利点があります。特別な理由がなければ、この記法を用います。
class Person constructor(
val name: String
)
プライマリコンストラクタのconstructor
キーワードは省略することが可能です。特別な理由がなければ、constructor
キーワードは省略した方が簡潔なコードとなります。
class Person (
val name: String
)
Kotlinでは、プライマリコンストラクタに加えて、クラス本体においてセカンダリコンストラクタを定義することが可能です。
以下の例では、引数なしでPersonクラスをインスタンス化した場合に、デフォルトの値を使ってPersonクラスをインスタンス化しています。セカンダリコンストラクタからプライマリコンストラクタを呼び出しています。
class Person (
val name: String
) {
constructor() : this("no name")
}
セカンダリコンストラクタは、引数の数や型が異なれば、複数宣言することも可能です。以下の例では、上記の例で宣言したセカンダリコンストラクタに加えて、String型の引数を2つ定義したセカンダリコンストラクタを宣言しています。
class Person (
val name: String
) {
constructor() : this("no name")
constructor(firstName: String, lastName: String) : this("$firstName $lastName")
}
プライマリコンストラクタと異なり、セカンダリコンストラクタは、コンストラクタ本体を持つことも可能です。コンストラクタ本体は、それが定義されるコンストラクタが呼び出された時に処理されます。
class Person (
val name: String
) {
constructor() : this("no name") {
println("constructor with no name")
}
constructor(firstName: String, lastName: String) : this("$firstName $lastName") {
println("constructor with first name and last name")
}
}
Kotlinではプライマリコンストラクタにデフォルト引数を定義することが可能であるため、セカンダリコンストラクタが必要とされる機会は限定的です。
クラス本体においてinit
キーワードを用いることで、初期化ブロックを宣言することが可能です。初期化ブロック内には、インスタンスの初期化処理を定義します。
class Person (
val name: String
) {
init {
doSomethingHere()
}
}
初期化ブロックは複数定義することが可能です。初期化ブロックを複数定義した場合は、上から宣言した順に呼び出されます。
class Person (
val name: String
) {
init {
doSomethingHere()
}
init {
doAnotherThingHere()
}
}
セカンダリコンストラクタのコンストラクタ本体と初期化ブロックが同時に宣言されている場合には、初期化ブロック、コンストラクタ本体の順に呼び出されます。
var
による変数の宣言var
キーワードを用いて変数を宣言することができます。var
キーワードを用いた変数の宣言は、以下の構文で行います。
var string: String
ここでString
は、変数の型を表します。変数名の後に:
を置き、半角スペースを開けて型を指定します。:
の後の半角スペースは無くても動作に問題ありませんが、ここに半角スペースを置くのが普通です。
宣言した変数への値の代入は、以下の構文で行います。
string = "string"
ここで重要なのは、変数stringはString型で宣言されているため、String型以外の値を代入しようとするとコンパイルエラーとなることです。例えば、以下のコードではString型で宣言された変数stringにInt型の値を代入しようとしているため、コンパイルエラーとなります。
string = 0
変数の宣言と同時に代入することも可能です。
var string: String = "string"
むしろ変数の宣言と同時に値を代入することのが普通です。
上記の構文を用いて変数の宣言時に値を代入する場合、値の型から変数の型を推論することが可能です(型推論)。この場合、変数の宣言から型の記述を省略することが可能です。
var string = "string"
型推論を用いない構文は型推論を用いた構文と比べて冗長であるため、右辺から容易に型を識別できる場合は積極的に型の記述を省略します。右辺から容易に型を識別できない場合は、一見して型を識別できるよう、冗長になっても型の記述を行う場合があります。型の記述の有無については、ケースバイケースで判断します。
var
キーワードで宣言した変数は再代入可能です。すなわち、一度値を代入した後に、再度別の値を代入することが可能ということです。以下のコードでは、trueOrFalse()
が返す結果に応じて、Int型の変数intに10または20を再代入しています。
var int: Int
if (trueOrFalse()) {
int = 10
} else {
int = 20
}
変数がvar
で宣言されている場合、コード内のどこで変数が変更されているかをプログラマーが追わなければならず、思わぬバグを生み出してしまう場合があります。そのため、次に示すval
を用いて、再代入のできない変数を宣言する方が安全なコードとなります。
val
による変数の宣言再代入を許すvar
キーワードによる変数の宣言に対して、val
キーワードによる変数の宣言では再代入を許しません。そのため、val
キーワードを用いて変数を宣言した方が安全なコードとなります。val
キーワードによる変数の宣言は、以下の構文で行います。var
キーワードによる変数の宣言と同様です。
val string = "string"
再代入の項で示したコードは、val
を用いて以下のように改善することができます。Kotlinのif
は値を返す式であるため、このように書くことができます。
val int = if (trueOrFalse()) { 10 } else { 20 }
if
式やwhen
式などを用いて、変数をvar
ではなくval
で宣言することで、より安全なコードとなります。