[Kotlin In Action學(xué)習(xí)筆記] [未完待續(xù)]
前言
使用kotlin進行android開發(fā)
kotlin非常適合開發(fā)android應(yīng)用程序,他將現(xiàn)代語言的所有優(yōu)勢帶入android平臺并且不會引入新的限制:
- 兼容性。kotlin與jdk6 完全兼容,并且主流IDE都支持kotlin語言。
- 性能。kotlin采用和java類似的字節(jié)碼結(jié)構(gòu),并且支持lambda等表達(dá)式使得kotlin與java的代碼運行類似或者更快。
- 互操作性。kot;in與java可以100%的互操作。允許使用現(xiàn)有的android庫。
- 學(xué)習(xí)曲線。kotlin對于java開發(fā)者入門十分簡單,IDE中的轉(zhuǎn)換器有助于開發(fā)者邁出第一步。
- 占用。kotlin具有緊湊的運行時庫,并且可以通過Proguard進一步減少。
- 編譯。kotlin支持高效的增量編譯。
用于android開發(fā)的工具
- kotlin android擴展是一個編譯器擴展,可以讓你擺脫編譯器中的findviewbyid()
- anko是一個圍繞android api的kotlin友好的包裝器的庫,以及可以使用kotlin代碼替換布局文件.xml的dsl
android開發(fā)入門
現(xiàn)在android studio/eclipse/intellij idea都已經(jīng)支持kotlin,其中android studio在3.0版本以后已經(jīng)默認(rèn)支持kotlin,用戶不用再下載kotlin插件,eclipse如何使用請自行g(shù)oogle,android studio3.0以前版本在settings-->plugins-->install jetbrains plugins搜索kotlin下載。下載之后重啟android studio,創(chuàng)建新項目完畢后,點擊菜單code-->convert java code to kotlin即可將項目自動生成的java代碼轉(zhuǎn)換成kotlin代碼。在菜單tools-->kotlin-->configure kotlin in project,選擇module和kotlin版本,一般直接確定即可。
kotlin android擴展
kotlin官方團隊的kotlin android擴展改進了對android支持,可以提高開發(fā)體驗。
開發(fā)者僅需要在module級別的build.gradle中添加
apply plugin: 'kotlin-android-extensions'
配置了之后,在xml文件中定義了id,在activity/fragment中,輸入這個id,android studio的代碼聯(lián)想會自動聯(lián)想到對應(yīng)的資源文件,并自動添加依賴
import kotlinx.android.synthetic.main.<布局>.*
這樣就省去了大量的findviewbyid代碼。
kotlin 對android 框架的支持
ButterKnife
ButterKnife可以直接將view和變量進行綁定從而免去調(diào)用findViewById。
另外,Kotlin Android 擴展插件(Android Studio 內(nèi)置)具有同樣的效果:使用簡潔明了的代碼替換findViewByid。 除非現(xiàn)在你正在使用 ButterKnife 而且沒有遷移計劃,那么前者非常值得嘗試。
在 Kotlin 中使用 ButterKnife 與 Java 中完全一致。 在 Gradle 構(gòu)建腳本的修改如下,后面將重點介紹代碼部分的差異。
在 Gradle 依賴中添加 kotlin-kapt 插件,并使用 kapt 替代 annotationProcessor。
apply plugin: 'kotlin-kapt'
dependencies {
...
compile "com.jakewharton:butterknife:$butterknife-version"
kapt "com.jakewharton:butterknife-compiler:$butterknife-version"
}
我們已經(jīng)將整個 ButterKnife 示例代碼轉(zhuǎn)換為 Kotlin, 參見詳細(xì)代碼。
讓我門看看發(fā)生了什么變化。 在 Java 中使用注解對將變量與之對應(yīng)的 view 進行綁定:
@BindView(R2.id.title) TextView title;
在 Kotlin 中使用屬性而不是直接使用變量。 對屬性使用注解:
@BindView(R2.id.title)
lateinit var title: TextView
@BindView 被定義為僅應(yīng)用于變量字段,而將注解應(yīng)用于整個屬性時,Kotlin 編譯器能夠理解并且覆蓋相應(yīng)注解的字段。
lateinit 修飾符允許聲明非空類型,并在對象創(chuàng)建后(構(gòu)造函數(shù)調(diào)用后)初始化。 不使用 lateinit 則需要聲明可空類型并且有額外的空安全檢測操作。
使用 ButterKnife 注解可以將方法設(shè)置為監(jiān)聽器:
@OnClick(R2.id.hello)
internal fun sayHello() {
Toast.makeText(this, "Hello, views!", LENGTH_SHORT).show()
}
以上代碼表示點擊“hello”按鈕后的事件響應(yīng)。 然而在 Kotlin 中使用 lambda 表達(dá)式會讓代碼更加簡潔清晰:
hello.setOnClickListener {
toast("Hello, views!")
}
Anko 庫默認(rèn)提供 toast 函數(shù)。
詳情請參閱kotlin@kotliner.cn
語法基礎(chǔ)
1. 基礎(chǔ)語法
定義包
包的聲明處于源文件的頂部
package com.dou.kotlin.learnkotlin
kotlin源文件和包的結(jié)構(gòu)和目錄無需匹配,也就是說源文件可以放在任何文件目錄下。
定義函數(shù)
函數(shù)使用關(guān)鍵子fun,參數(shù)格式為 參數(shù):類型
// java轉(zhuǎn)kotlin自動生成的oncreate
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
// 參數(shù):(Int, Int),無返回值函數(shù)
fun printSum (a : Int, b : Int) : Unit {
println("sum is " + (a + b))
}
// 參數(shù):(Int, Int),無返回值函數(shù),unit類型可以省略
fun printSum (a : Int, b : Int) {
println("sum is " + (a + b))
}
// 參數(shù):(Int, Int), 返回:(Int)
fun sum (a : Int, b : Int) : Int {
return a + b
}
// 參數(shù)(Int, Int), 返回(Int)
// 表達(dá)式作為函數(shù)體,返回類型自動推斷:
fun mutilply (a : Int, b : Int) = a * b
// 參數(shù)(Int, Int), 返回(Int)
fun mutilply (a : Int, b : Int) : Int = a * b
注釋
行注釋
// 這是行注釋
多行注釋
/*這是多行注釋
*/
2. 基本數(shù)據(jù)類型
定義變量
定義一次賦值的變量
定義一次賦值的變量使用val修飾
val a : Int = 1 //立即賦值,定義變量類型為Int
val b = 2 //立即賦值,變量類型自動判斷為Int
val c : Int //如果沒有初始賦值必須定義變量類型
c = 3 // 明確賦值
定義可變變量
var a : Int = 3
var b = 3
var c : Int //如果沒有初始賦值必須定義變量類型
c = 3
使用字符串模板
字符串模板就是一小段代碼表示一個字符串。字符串模板以$表示
var a = 1
var b = "a is $a"
a = 2
var d = "${b.replace("is", "was")}, but now is $a"
3. 條件控制
if條件表達(dá)式
// 條件表達(dá)式
fun method4 (a : Int, b : Int) : Int{
if (a > b) {
return a
} else {
return b
}
}
// 條件表達(dá)式,將函數(shù)式作為函數(shù)體
fun method5 (a: Int,b: Int) = if (a > b) a else b
when條件表達(dá)式
when相當(dāng)于java中的switch語句。
它的簡單形式是
when (參數(shù)) {
條件 -> 語句 // 參數(shù)符合條件的情況
else -> 語句 // 其它情況
}
或者
when {
條件表達(dá)式 -> 語句 // 符合條件表達(dá)式的時候執(zhí)行
else -> 語句 //其它情況
}
when將它的參數(shù)和所有分支條件順序比較,知道某個分支滿足條件。如果其它分支都不滿足條件,就會執(zhí)行else分支,如果when作為表達(dá)式使用,則必須指定else語句。
fun method16 () {
var a = 9;
when {
a in 1..10 -> println("$a is in 1-10")
a == 1 -> println("$a == 1")
else -> println("other")
}
when (a) {
!in 1..10 -> println("$a is not in 1-10")
1 -> println("$a == 1")
else -> println("other")
}
fun hasPrefix (a: Any) = when (a) {
is String -> a.contains("prefix")
else -> false
}
}
4. 循環(huán)控制
for循環(huán)
for循環(huán)可以對任何提供迭代器的對象進行遍歷,基本語法為
for (a: Int in arrays) {
// ...
}
對集合進行遍歷
var items = listOf<String>("kotlin","java", "c", "c++");
for (i in items) {
println(i)
}
for (i in items.indices) {
print(items[i])
}
while循環(huán)
while循環(huán)基本的語法為
while(布爾表達(dá)式) {
// 語句
}
do {
// 執(zhí)行語句
} while (布爾表達(dá)式)
跳轉(zhuǎn)和返回
kotlin中跳轉(zhuǎn)和返回與java類似,有break,return,continue。
kotlin中所有表達(dá)式都可以用標(biāo)簽標(biāo)示。標(biāo)簽格式為 標(biāo)識符后加@符號,例如abc@,mark@,要為一個表達(dá)式添加標(biāo)簽,需要在這個表達(dá)式前加上標(biāo)簽即可。
loop@ for (i in 1..10) {
}
標(biāo)簽可以配合continue和break使用。當(dāng)有多層嵌套時,可以指定跳出到哪個循環(huán)體.
outer@ for (i in 1..20) {
inner@ for (j in 1..20) {
if (...) break@outer
}
}
5. 其它
使用可空值和空值檢測
當(dāng)某個變量可以為空時,必須在變量類型聲明后使用?表示該變量可以為空
fun method6 (a : String?) {
if (a == null) {
println("a為空")
} else{
println(a)
}
}
kotlin的空安全設(shè)計對于聲明可能為空的參數(shù),在使用時要做判空處理,一般有兩種處理方式:
- 變量后加!!表示為空時拋出異常
- 變量后加?表示不作處理返回null或者配合?:做空判斷處理
// 后邊加?表示變量可能為空
var a : String? = null
// 變量后加!!表示拋出異常
var b = a!!.toInt()
// 變量后加?表示返回null時不做處理
var c = a?.toInt()
// ?配合?!做空判斷處理
var d = a.toInt() ?: -1
類型檢測
is運算符用來檢測某個對象是否是某種類型的實例,相當(dāng)于java中的instance of,在檢測后,如果是某種類型的話,就可以直接當(dāng)做該類型使用,不用顯式的去轉(zhuǎn)換
if (obj is String) {
return obj.length
} else {
return null
}
使用區(qū)間
使用集合
2. 習(xí)慣用法
3. 編碼習(xí)慣
Kotlin基礎(chǔ)
筆記丟失了一部分之后再補上
數(shù)組
fun method18(){
var items = arrayOf(1,2,3,4) // 創(chuàng)建一個確定的數(shù)組[1,2,3,4]
for (i in items) {
print(i)
}
var array1 = arrayOfNulls<Int>(4) // 創(chuàng)建一個空數(shù)組
for (i in array1.indices) {
array1[i] = i // 給數(shù)組元素賦值
}
}
// Array是一個工廠函數(shù), 第一個參數(shù)指定數(shù)組的大小,第二個參數(shù)表達(dá)式是根據(jù)數(shù)組索引指定每個元素的值
// 創(chuàng)建數(shù)組["1", "4", "9", "16"]
var array2 = Array(4, {i -> (i * i).toString()})
字符串
字符串用strng類型表示,字符串是不可變的。字符串的元素可以通過s[i]訪問。也可以用for循環(huán)迭代字符串。
字符串分為原生字符串和轉(zhuǎn)義字符串。
轉(zhuǎn)義字符串類似java中的字符串,用""包含起來,可以使用轉(zhuǎn)義字符。
原生字符串使用""" """包含起來,可以包括換行和任意文本。
默認(rèn)|作為邊界前綴。
fun method19 () {
var str = """
|這是原生字符串
|這是原生字符串
|這是原生字符串
"""
// 輸出 |這是原生字符串
// 輸出 |這是原生字符串
// 輸出 |這是原生字符串
var strTrim = """
|這是原生字符串
|這是原生字符串
|這是原生字符串
""".trimMargin() // 輸出 這是原生字符串
這是原生字符串
這是原生字符串
var strCode = """
for (i in 1..4) {
print(i)
}"""
println(str)
println(strTrim)
println(strCode)
}
類和對象
類
kotlin中也是用關(guān)鍵字class聲明類。
類聲明由類名,類頭(指定類繼承,類構(gòu)造方法等)和大括號包起來的類體組成,如果一個雷沒有類體可以省略大括號。
類中可以有一個主構(gòu)造方法和多個次構(gòu)造方法,主構(gòu)造方法是類頭的一部分,跟在類名之后的,用constructor關(guān)鍵字修飾。如果主構(gòu)造函數(shù)沒有任何注解或者修飾可以省略。
class Person constructor(name: String)
class persion(name: String)
主構(gòu)造函數(shù)不能包含任何代碼。類的初始化操作可以放在類中init關(guān)鍵字的代碼塊中。
class Persion(name: String, id: Long) {
var pName: String = name
var pId: Long = id
init {
// ...
}
}
主構(gòu)造方法可以直接聲明屬性。
class Persion(var name: String, var id: Long) {
init {
// ...
}
}
次構(gòu)造方法的格式為
constructor(參數(shù): 參數(shù)類型) : this(...參數(shù))
this(...參數(shù))指代的是其它構(gòu)造方法。如果這個類中沒有主構(gòu)造方法是可以省略的。如果類中有構(gòu)造方法則這個類必須直接或者間接的委托主構(gòu)造方法。委托到另一個構(gòu)造方法用this關(guān)鍵字即可。
如果一個非抽象類沒有聲明任何構(gòu)造方法,那么這個類會默認(rèn)一個public的無參的主構(gòu)造方法。
要創(chuàng)建類的實例不需要且沒有java中的new關(guān)鍵字
類成員包括
- 函數(shù)
- 屬性
- 嵌套類和內(nèi)部類
- 對象聲明
屬性
屬性聲明
在類中可以用var修飾可變成員屬性和val修飾只讀成員屬性。
要使用一個屬性只用在對象后.該屬性名即可。
var extendence = Extendence(1)
print(extendence.name)
Getters和Setters
聲明一個屬性的完整語法是:
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
初始化器,getter,setter方法都是可選的
var allByDefault: Int? // 錯誤:需要顯式初始化器,隱含默認(rèn) getter 和 setter
var initialized = 1 // 類型 Int、默認(rèn) getter 和 setter
繼承
要去聲明一個顯式的超類,在類頭的最后加上:(超類名)(超類的構(gòu)造方法)
open class Base(p: Int)
class Extendence(p: Int) : Base(p)
如果子類有主構(gòu)造方法那么這個子類聲明中必須要用子類的構(gòu)造方法參數(shù)對父類進行初始化。如果子類沒有主構(gòu)造方法,那么在每個次構(gòu)造方法必須使用super關(guān)鍵字初始化父類類型或者委托給其它的構(gòu)造函數(shù)做到這一點。
class Extendence : Base{
constructor(p: Int) : super(p)
constructor(p:Int, a: Int) : this(p)
}
Any
Any是所有類的超類,但是Any類中只有三個方法,equals(),toString(),hashCode()。
fianl,open關(guān)鍵字
open代表該類可以被繼承,類默認(rèn)是final修飾的,也就是不能被繼承。
覆蓋方法
kotlin需要顯式的標(biāo)注可被覆蓋的成員和被覆蓋的成員。
open class Base(p: Int) {
open fun method(){}
}
class Extendence : Base{
constructor(p: Int) : super(p)
constructor(p:Int, a: Int) : this(p)
override fun method(){}
}
也就是說方法覆蓋中父類和子類方法都要加修飾。父類的方法前要加open,子類方法要加override。如果父類方法沒有用open修飾,子類不允許出現(xiàn)與父類相同簽名的方法(同名同參同返回值)。
標(biāo)記為override的成員本身也是開放的,可以被再次覆蓋,如果想要禁止再次覆蓋,需要使用final關(guān)鍵字。
open class Entendence(p: Int) : Base(p){
final override fun method(){}
}
覆蓋屬性
覆蓋屬性的基本用法和覆蓋方法類似。父類屬性用open修飾,子類屬性用override修飾。
你可以用一個var屬性覆蓋一個val屬性,但是不能用val屬性覆蓋一個var.因為var屬性本質(zhì)上聲明了一個getter和setting方法,val屬性本質(zhì)上只能聲明getter方法。
覆蓋規(guī)則
kotlin支持多繼承,如果一個子類繼承多個父類且父類中存在同樣的屬性或者方法,那么這個子類必須覆蓋這個方法。
open class A(p: Int){
open fun f(){}
fun v()}{
}
interface B{
fun f(){}
fun v(){}
}
class C(p: Int) : A(P),B{
override fun f() {
super<A>.f();
super<B>.f();
}
fun v(){}
}
抽象類
類或者類中的成員可以被聲明為abstract,被聲明為抽象的對象默認(rèn)是開放的。
需要注意的是我們可以用抽象的成員去覆蓋飛抽象成員。
伴生對象
伴生對象的作用類似與java中的靜態(tài)成員