Kotlin 學習筆記(一)基礎語法、類、屬性的探索

前言
本文章只是用於記錄學習,所以部分地方如果有錯誤或者理解不對的地方,麻煩請指正。

#工具

  1. android 開發的話 可以使用 android studio ,在新建項目的時候記得勾選 supper kotlin 就可以了,和jni 開發操作相似的。進入android studio之後如果是 3.0 以後的版本,都是自帶kotlin 插件的,如果是 as3.0一下的版本則需要在 File /setting / plugins / 搜索 kotlin 安裝重啓。
  2. 平時跟我一樣在學習的話,可以使用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)

Kotlin 學習筆記(二)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章