來了解一下各方對 Kotlin 的見解
然後也提供一下學習資源 : Kotlin官方文檔
本篇大部分內容都是參考 Kotlin 的官方文檔來的,可以去該網站多挖挖寶
以下開始一些基礎介紹
- Variables
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val number: Int = 1 //>> same as "final int number = 1;" in Java | |
val number = 1 //>> Kotlin will infer type of number is Int。similar to "auto number = 1;" in C++ | |
val number: Int //>> if no initial value, type must be given | |
number = 3 |
在 Kotlin,變數預設是 non-null type,也就是不能是 null
Kotlin 的一大特色就是能盡量減少 NullPointerException 發生的機率
以下是關於變數 null safety 的介紹
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var a: String = null //>> a is non-null type, compilation error | |
var b: String? = null //>> b is nullable, okay | |
val lengthA = a.length //>> okay because a is non-null type | |
val lengthB = b.length //>> error because b might be null. see following usage | |
//>> Usage 1: | |
//>> use safe call operator, written as ?. | |
//>> b?.length return b.length if b is not null and null otherwise | |
//>> the type of lengthB is Int? | |
val lengthB = b?.length | |
//>> Usage 2: | |
//>> let lengthB has default value when b is null and type of lengthB is Int instead of Int? | |
val lengthB: Int = if (b != null) b.length else -1 //>> method 1 | |
val lengthB = b?.length ?: -1 //>> method 2, use Elvis operator, written as ?: | |
//>> Usage 3: | |
//>> use !! operator if you want NullPointerException | |
//>> there will be a NullPointerException when b is null | |
val lengthB = b!!.length |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//>> the as? will return null if the cast was not successful | |
val newInt: Int? = someVar as? Int |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MyKotlinClass { | |
private var mMsg: String //>> compilation error. non-null type need initial value | |
fun initMsg() { | |
mMsg = "init" | |
} | |
} | |
//>> use lateinit keyword | |
class MyKotlinClass { | |
private lateinit var mMsg: String | |
fun initMsg() { | |
mMsg = "init" | |
} | |
} |
(1) 只能用在 var 變數
(2) 不能用在 primitive type (Int, Float, ...)
(3) 該變數不能有客製化的 setter 和 getter
- Functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fun getSum(a: Int, b: Int): Int { | |
return a+b | |
} | |
//>> can be simplified further | |
//>> Kotlin will infer return type | |
fun getSum(a: Int, b: Int) = a + b |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//>> no return value | |
fun showMsg(msg: String): Unit { | |
println(msg) | |
} | |
//>> omit Unit | |
fun showMsg(msg: String) { | |
println(msg) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fun doAction(msg: String, isTestMode: Boolean = false, ver: Int = 1) { | |
//>> function body | |
} | |
//>> use named arguments | |
doAction("Hello Kotlin", ver = 3, isTestMode = true) |
使用 vararg 有幾點注意事項
- function 只能有一個 parameter 被標示為 vararg
- vararg parameter 通常要放在 parameter list 的最後一個。如果不是最後一個,則在使用的時候,必須搭配 named argument 來使用
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//>> function with variable number arguments | |
fun <T> toList(vararg input: T) : List<T> { | |
val result = ArrayList<T>() | |
input.forEach { n -> result.add(n) } | |
return result | |
} | |
//>> example 1 | |
val list = toList(1, 2, 3, -1, -2, -3) | |
//>> example2 | |
//>> use * to spread array a | |
val a = arrayOf(1, 2, 3) | |
val b = toList(7, 5, *a, -5) | |
//========================================================== | |
//>> vararg is not the last one in the list | |
fun <T> toList(vararg input: T, ver: Int ) : List<T> { | |
val result = ArrayList<T>() | |
input.forEach { n -> result.add(n) } | |
return result | |
} | |
//>> need to use named argument syntax to pass following parameter | |
val list = myKotlinClass.toList(1, 2, 3, ver = 111) |
- Class
class 的基本宣告方式如下
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//>> this class cannot be inherited | |
class MyClass { | |
//>> class body | |
} | |
//>> this class can be inherited | |
open class MyClass { | |
//>> class body | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//>> create instance of class | |
val myClass = MyClass() //>> there is no 'new' keyword in Kotlin |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//>> this class will have auto-generated constructor with no arguments | |
//>> the auto-generated constructor's visibility will be public | |
class MyClass { | |
//>> class body | |
} | |
//>> this class has a public primary constructor with one argument | |
class MyClass constructor(msg: String) { | |
//>> class body | |
} | |
//>> you can omit the constructor keyword when primary constructor has no | |
//>> annotations or visiblity modifiers | |
class MyClass(msg: String) { | |
//>> class body | |
} | |
//>> want a private primary constructor | |
class MyClass private constructor(msg: String) { | |
//>> class body | |
} | |
//>> constructor example 1 | |
class MyKotlinClass(msg: String, ver: Int) { | |
private var privateMsg = "[private]" + msg | |
private var privateVer = ver + 20 | |
fun setup() { | |
Log.d("TAG", "private message is $privateMsg, private version is $privateVer") | |
} | |
} | |
//>> constructor example 2 | |
class MyClass(val msg: String, var ver: Int) { | |
private var privateMsg = "[private]" + msg | |
fun setup() { | |
Log.d("TAG", "user's message is $msg, current version is $ver") | |
ver = -1 //>> change the value | |
Log.d("TAG", "private message is $privateMsg, modified version is $ver") | |
} | |
} | |
usage: | |
val myKotlinClass = MyKotlinClass("Hi Kotlin", 33) | |
myKotlinClass.setup() | |
=> outputs are: | |
user's message is Hi Kotlin, current version is 33 | |
private message is [private]Hi Kotlin, modified version is -1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//>> use initializer block to contain code for primary constructor | |
class MyClass(msg: String) { | |
init { | |
Log.d("TAG", "user's message is $msg") | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//>> this class has no customized primary constructor | |
//>> and has one secondary constructor | |
class MyClass { | |
constructor(secondMsg: String) { | |
println("second message is ${secondMsg}") | |
} | |
} | |
//>> if the class has a primary constructor | |
//>> then each secondary constructor need to delegate to the primary constructor | |
class MyClass(msg: String) { | |
constructor(msg:String, number: Int) : this(msg){ | |
println("[$number] message is $msg") | |
} | |
constructor(msg: String, number: Int, ver: Double) : this(msg) { | |
println("[$number] message is $msg and version is $ver") | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//>> Java Style | |
public class MyJavaClass { | |
public MyJavaClass(String msg, int number) { | |
this(msg, number, 1.8); | |
} | |
public MyJavaClass(String msg, int number, double ver) { | |
Log.d("MyJavaClass", "[" + number + "] message is " + msg + ", and version is " + ver); | |
} | |
} | |
=> val myJavaClass = MyJavaClass("Hi Java", 23) | |
output: [23] message is Hi Java, and version is 1.8 | |
=> val myJavaClass = MyJavaClass("Hi Java", 23, 6.6) | |
output: [23] message is Hi Java, and version is 6.6 | |
//>> Kotlin Style | |
class MyKotlinClass { | |
constructor(msg: String, number:Int, ver: Double = 1.8) { | |
Log.d("MyKotlinClass", "[$number] message is $msg, and version is $ver") | |
} | |
} | |
=> val myKotlinClass = MyKotlinClass("Hi Kotlin", 33) | |
output: [33] message is Hi Kotlin, and version is 1.8 | |
=> val myJavaClass = MyJavaClass("Hi Kotlin", 33, 10.2) | |
output: [33] message is Hi Kotlin, and version is 10.2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//>> if the derived class has primary constructor | |
//>> the base class must be initialized right here | |
open class Base(msg: String) { | |
//>> class body | |
} | |
class Derived(msg: String) : Base(msg) { | |
//>> class body | |
} | |
//>> if the derived class has no primary constructor | |
//>> each secondary constructor must use super to initialize base class | |
open class Base(msg: String) { | |
//>> class body | |
} | |
class Derived : Base { | |
constructor(msg: String, ver: Int) : super(msg) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open class Base { | |
fun doAction() { | |
//>> function body | |
} | |
open fun showMsg() { | |
//>> function body | |
} | |
} | |
class Derived : Base() { | |
//>> this is a compilation error | |
//>> derived class can only override open function | |
override fun doAction() { | |
//>> function body | |
} | |
//>> okay | |
override fun showMsg() { | |
//>> function body | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open class BaseClass { | |
open fun doAction() { | |
println("don't do it") | |
} | |
open fun showMsg() { | |
println("Hi Kotlin") | |
} | |
} | |
interface BaseInterface { | |
//>> interface members are 'open' by default | |
fun doAction() { | |
println("just do it") | |
} | |
fun power() { | |
println("interface only") | |
} | |
} | |
class Derived : BaseClass(), BaseInterface { | |
//>> doAction() must be override because both BaseClass and BaseInterface have doAction() | |
override fun doAction() { | |
super<MyKotlinClass>.doAction() //>> call to BaseClass.doAction() | |
super<BaseInterface>.doAction() //>> call to BaseInterface.doAction() | |
} | |
} |
而在這種情況下,要指定使用哪個 supertype 的 doAction(),就可以使用 super<BaseName> 來指定
至於 showMsg() 和 power(),因為來源都只有一個,所以不會被強迫要求用 override 複寫
- What's Next
不過也可以看出來,Kotlin 在某些部分也有一些限制,像是為了 null safety,programmer 必須在寫 code 的時候遵從一些語法才行
下一篇會繼續介紹 Kotlin 的基礎語法,讓各位更熟悉 Kotlin