前言
本文章只是用於記錄學習,所以部分地方如果有錯誤或者理解不對的地方,麻煩請指正。
#工具
- android 開發的話 可以使用 android studio ,在新建項目的時候記得勾選 supper kotlin 就可以了,和jni 開發操作相似的。進入android studio之後如果是 3.0 以後的版本,都是自帶kotlin 插件的,如果是 as3.0一下的版本則需要在 File /setting / plugins / 搜索 kotlin 安裝重啓。
- 平時跟我一樣在學習的話,可以使用idea ,新建kotlin 項目,在裏邊聯繫就可以了。
1. HelloWorld 及 包的聲明
在Kotlin中定義包與Java有點不同,在Kotlin中目錄與包結構無需匹配,
Kotlin的源碼可以在磁盤上的任意位置。
// 包格式 和 java 一致
package com.ymc.hellokotlin
fun main(args: Array<String>) {
println("Hello world")
println(max(2,3))
}
fun max(a:Int ,b:Int):Int{
return if(a>b) a else b;
}
1. main 函數不需要在class 中就可以運行
2. fun 代表一個函數,後邊緊跟函數名稱,參數列表和返回值類型
3. 參數實現寫 參數名稱 然後冒號隔開,再寫參數類型(和java 相反)
4. 函數的返回值是在後邊的(和java剛好相反的)當然 有返回值 也可以不寫返回類型(前提是:只有表達式體 函數返回類型可以省略,如果是代碼塊體函數就必須要 寫明函數返回類型),因爲kotlin 通過 類型推導 也是可以知道返回值類型的
5. system.out.println 被包裝爲 println
6. 在行末可以省略 分號 (類似 js)
7. 看到max函數中 if類似於三元表達式 kotlin中,if 是有結果值的表達式
8. 如果返回值 類似於 java 中的 void 則可以寫成 :Unit ,當然也可以省略不寫
在kotlin 中,除了部分循環(for do 和 do/while)大多控制結構都是表達式,是有返回值的。另一方面 java 中的賦值語句爲表達式,而kotlin 中則爲語句。
與Java定義包名一樣,在源文件的開頭定義包名:但是不同的是,包名和文件夾路徑可以不一致:源文件可以放在項目的任意位置,當然也不建議這樣搞,自己何苦爲難自己。。。
2. 變量
考慮到kotlin 的變量聲明是可以省略 類型的,所以kotlin 變量聲明有別於java ,kotlin 變量聲明順序爲 關鍵字 變量名稱 類型(可不加),如果變量沒有初始化 則需要明確表明 變量類型。
常量與變量都可以沒有初始化值,但是在引用前必須初始化編譯器支持自動類型判斷,即聲明時可以不指定類型,由編譯器判斷。如果不在聲明的時候初始化則必須提供變量的類型
val name = "ymc"
val age = 23
val age1 : Int = 23
val age2 :Int
age2 = 24
val :不可變引用 ,在val聲明變量後不能再初始化之外再次賦值(java final)
var :可變引用 , 該類型變量可以隨便賦值
*** 官方推薦** 儘量使用val 聲明變量,使程序更接近函數式編程風格
1、可變變量的定義: var 關鍵字
var <變量名> : <變量類型> = <初始值>
var sum: Int = 3
sum = 8
//由於編譯支持類型推導可以省略Int類型
var sum = 3
sum = 8
2、不可變變量的定義: val 關鍵字, 不能進行二次賦值,類似Java中的final類型
val <常量名> : <常量類型> = <初始值>
val sum: Int //沒有賦值初始化之前必須指定類型
sum = 5
已知值的屬性可以使用 const 修飾符標記爲 編譯期常量。需要滿足如下幾種條件 (類似 java 中的 constanUtil 中的 常量值)
- 位於頂層或者是 object 的一個成員
- 用 String 或原生類型 值初始化
- 沒有自定義 getter
const val SUBSYSTEM_KEY: String = "key"
@Deprecated(SUBSYSTEM_KEY) fun foo() { …… }
3 .字符串模版
println("Hello world $name") // $變量
println("Hello world ${age[0]}") // ${變量}
println("Hello world " + name) // 原來的方法也是可以繼續使用的
var a = 1
a = 2
var s1 = "a is $a"
val s2 = "${s1.replace("is", "was")}, but now is $a"
4. 類和屬性
4.1 類
接下來 我們比較一下 java 和 kotlin 中類的寫法的不同
java
public class DemoBean {
private final String name;
public DemoBean(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
kotlin
class DemoBean(val name: String)
如果您跟我一樣也是落後的kotlin初學者,我們可以在日常生活中還是以 java 語言開發爲主 ,如果需要看kotlin 的效果的時候,我們可以將java 代碼複製到 kt文件中,idea會自動提示我們轉換。
4.2 屬性
類 ,也就是我們將數據和處理數據的代碼封裝成一個單一的實體。
class Person{
var name :String = "ymc" // 可讀可寫
val isMarried : Boolean = false // 只讀
}
上段代碼中 isMarried 會生成一個字段,一個getter 和一個 setter ,而 name 則會生成一個字段 和 一個 getter 。
kotlin 在你聲明屬性的時候,你就聲明瞭對應的訪問器,默認的訪問器 就是返回值的 getter 和 更新數值的 setter ,kotlin 會暴漏一個 getName 方法,當然我們也可以自定義訪問器。
fun main(args: Array<String>) {
var person = Person()
println(person.name +";"+ person.isMarried )
}
可以看到我們直接調用而不需要get,感覺很像js…
4.3 自定義訪問器
class Person{
var name :String = "ymc"
var sex : Int = 0; // 0 爲女性 1爲男性
val isMarried : Boolean = false
val isBoy :Boolean
get() {
return if(sex==1) true else false
}
}
我們將Person 添加 sex 和 isboy 屬性,重寫getter ,這樣就可以做到自定義訪問器。
如果 我們設置 屬性爲 val 但是通過自定義 getter 修改屬性那麼 屬性會修改麼?
fun main(args: Array<String>) {
val name = "Hello Kotlin"
name = "Hello Java"
}
如果單純的 修改 則會報錯
Error:(8, 5) Kotlin: Val cannot be reassigned
接下來我們通過 自定義訪問器 看看
class RandomNum {
val num: Int
get() = Random().nextInt()
}
fun main(args: Array<String>) {
println("the num is ${RandomNum().num}")
}
the num is -1251923160
the num is -1527833641
總結: 由以上的例子可以說明假設一是成立的,在Kotlin中的val修飾的變量不能說是不可變的,而只能說僅僅具有可讀權限。
4.4 備用字段
kotlin 中並不允許使用 字段,這個時候 我們就可以使用備用字段,比如下段 代碼,起到局部變量的作用。
//初始化值會直接寫入備用字段
var counter = 0
get() = field // field可以理解爲自己本身
set(value) {
if (value >= 0)
field = value
}
// 這種情況並不需要備用字段,所有不會生成備用字段
val isEmpty: Boolean
get() = this.size == 0
注意:field標識符只允許在屬性的訪問器函數內使用.
4.5 延遲初始化屬性和變量
屬性聲明爲非空類型必須在構造函數中初始化,爲處理這種情況,你可以用 lateinit 修飾符標記該屬性:
public class MyTest {
lateinit var subject: TestSubject
@SetUp fun setup() {
subject = TestSubject()
}
@Test fun test() {
subject.method() // 直接解引用
}
}
這樣的話,我們就可以不用再構造函數的時候對其進行初始化,後續在哪裏需要 調用 setup就可以。
5. null檢查機制
Kotlin的空安全設計對於聲明可爲空的參數,在使用時要進行空判斷處理,有兩種處理方式,字段後加!!像Java一樣拋出空異常,另一種字段後加?可不做處理返回值爲 null或配合?:做空判斷處理
//類型後面加 ? 表示可爲空
var age: String? = "23"
//字段後面加 "!!" ,如果爲null則拋出空指針異常
val ages = age!!.toInt()
//字段後面加 ”?“ 如果爲null不做處理返回 null
val ages1 = age?.toInt()
//使用 ”?:“ 表示age爲null返回-1
val ages2 = age?.toInt() ?: -1
kotlin 中如果 數值 或 返回值可以爲 空的時候 則可以在 類型後邊加上 ?
fun getStringLength(obj: Any): Int? {
if (obj is String) {
// `obj`在這個分支中自動轉換爲`String`類型
return obj.length
}
// `obj`仍然是`Any`類型
return null
}
fun getStringLength(obj: Any): Int? {
// `obj`在這個分支中自動轉換爲`String`類型
if (obj !is String) return null
return obj.length
}
該方法返回值可以爲 null 也可以是 int 類型 字符串的長度,在判斷中我們有看到了新的 詞語 is ,is 表達式主要檢查 表達式或者值 的類型是否是 is 後邊的類型,如果是 則會進行自動轉換,如果不是則 仍然保持原來的數據類型。
上段代碼中我們可以看到 kotlin 和 java 的類型轉換的差別,java 使用instanceOf 來判斷類型後,如果要轉型需要 顯式將該類型轉換爲我們比較的類型,而 kotlin 中 使用 is 檢查過 數據後,如果類型正確 則會 智能轉型,這一步是編譯器自動幫我們完成的。
當然如果我們需要使用 顯式轉換的時候 可以使用 as 表達式,(val n = A as Num)