Kotlin:基礎(chǔ)語法學習(二)

本篇內(nèi)容清單如下:

  • 函數(shù)
  • 變量
  • 基本類型
  • 控制流

一、基本語法

1. 包定義與導入

  • 同 Java,在文件頂部聲明:package(修飾符) 包名 。
  • 源文件的 所有內(nèi)容(類、函數(shù))都包含在 聲明的 包內(nèi)。
  • 若沒有指明包名,則文件內(nèi)容屬于 無名字的 默認包。

導入:

  • 導入包:import packageName。
  • 若出現(xiàn)類名沖突,則可使用 as 關(guān)鍵字本地重命名消除歧義?!?】
import org.example.Message
import org.test.Message as TestMessage

import 關(guān)鍵字使用場景:

  • 導入「類」
  • 導入 「頂層函數(shù) 及 屬性」
  • 導入 在 「對象聲明」 中聲明的函數(shù)和屬性;
  • 導入「枚舉常量」。

2. 程序入口

kotlin 應(yīng)用程序的入口點是 main 函數(shù)。(雖如此,但是以下 main 無法再 AS 中識別。)

fun main() { println("hello word !") }

// 可識別運行的 main 方法
companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            println("hello word !")
        }
}

3. 函數(shù)

  • 聲明:使用 fun 關(guān)鍵字。
  • 形式:fun 函數(shù)名(參數(shù)名: 類型, 參數(shù)名: 類型): 返回值類型 { // 函數(shù)體 } 。每個參數(shù),必須有顯式類型。
  • 調(diào)用:sum(1 + 2)

一個加法函數(shù)的兩種寫法:

// 1. 完整寫法
fun sum(a: Int, b: Int): Int {
  return a + b
}

// 2. 函數(shù)體僅含 單個表達式,并且 返回值 可 自動推斷類型
fun sum(a: Int, b: Int) = a + b

// 3. 返回值無意義(類比 void),則 Unit 返回類型可省略
fun printSum(a: Int, b: Int): Unit {  // =>  fun printSum(a: Int, b: Int) { ... }
   println("sum of $a and $b is ${a + b}")
}

以上為一般函數(shù)調(diào)用,當然還有其他函數(shù)類型寫法與調(diào)用,存在一些不同。同函數(shù)相關(guān)的內(nèi)容主要有以下這五點:

  • 函數(shù)聲明
  • 函數(shù)參數(shù)
  • 函數(shù)返回值
  • 函數(shù)調(diào)用
  • 函數(shù)作用域

與 Java 很大不同的內(nèi)容點:

  • 默認參數(shù) && 具名參數(shù) && 可變參數(shù)
  • 中綴表示法
  • 局部函數(shù)(閉包)
  • 擴展函數(shù)
  • 高階函數(shù) && Lambda 表達式

根據(jù)文檔整理出來的導圖(函數(shù)作用域后續(xù)文章還會繼續(xù)說道)如下:


Kotlin 函數(shù)相關(guān)概念總結(jié)

[說明:星星 - 新概念且重要,問號 - 暫不理解,紅旗 - 新概念但不重要。]

備注:

  • 主構(gòu)造函數(shù)很特別,參數(shù)可以使用 val 或 var 聲明,但是普通函數(shù)不能用。次構(gòu)造函數(shù)沒啥大差別。
class Person constructor() { }

class Person constructor(name: String)

class Person(name: String)

class Person public constructor(name: String)

class Person(name: String) {
    var children: MutableList<Person> = mutableListOf()
    // 次構(gòu)造函數(shù),必須要委托給 主構(gòu)造函數(shù)
    constructor(name: String, parent: Person)  : this(name) {
        parent.children.add(this)
    }
}

4. 變量

兩種類型:

  • 只讀變量,使用關(guān)鍵字 val 定義。只能為其賦值一次。
  • 可重新賦值的變量,使用關(guān)鍵字 var 定義。

變量又可分為:

  • 頂層變量:在文件最頂部聲明的變量
  • 屬性與字段:類中或函數(shù)中聲明與定義。
val a: Int = 1 // 立即賦值
val b = 2       // 自動推動出類型,可省略 參數(shù)類型
// b = 3         // 重新賦值,編譯器會報錯
 
var x = 5      // 自動推斷類型
x += 5

二、基本類型

在 Kotlin 中,也是 “一切皆為對象”。但有些類型 可以在運行時,表示為「原生類型值」,如 數(shù)字、字符以及布爾值。

Kotlin 中的基本類型:

  • 數(shù)字:Byte、Short、Int、Long、Float、Double
  • 字符:Char
  • 布爾值:Boolean / true false
  • 數(shù)組:Array
  • 字符串:String
1. 數(shù)字
  • Long、Float、Double 類型同 Java 一致,后面可帶 L、f/F、D 。
  • Kotlin 中「無隱式拓寬轉(zhuǎn)換」,如具有 Double 類型參數(shù)的函數(shù),只能接收 Double 類型的值,而不能對 Float、Int 或其他數(shù)字值調(diào)用。
  • 若需要原生類型 對應(yīng)的 可空引用泛型,如 Int 可空引用對應(yīng)為 Int?,后者會把數(shù)字進行裝箱。 [注:數(shù)字裝箱不一定保留同一性。=== 判斷同一性。 ]

每個數(shù)字類型 都支持如下 轉(zhuǎn)換函數(shù):

  • toByte(): Byte
  • toShort(): Short
  • toInt(): Int
  • toLong(): Long
  • toFloat(): Float
  • toDouble(): Double
  • toChar(): Char
2. 字符
  • 不能直接當做數(shù)字。
  • 字面值使用單引號 '1' 。
3. 布爾
  • 同 java ,值 true 與 false 。
  • 布爾運算:|| 、 &&、 !
4. 數(shù)組
  • 用 Array 表示,定義可 get 與 set 函數(shù),可以轉(zhuǎn)變?yōu)?[] 。
  • 構(gòu)建數(shù)組:arrayOf(1, 2, 3)
  • 原生類型數(shù)組:ByteArray、IntArray 等。
5. 字符串
  • 用 String 表示。字符串是不可變的,元素訪問,可用索引運算符訪問:s[i] 。
  • 訪問字符串:for (c in str) { } 、str[0]
  • 拼接字符串,可以使用操作符 +,但不建議,一般都使用 字符串模板 $原始字符串。
原始字符串
  • 原始字符串:使用三個引號 (""") 分解符,內(nèi)部 無轉(zhuǎn)義 且 包含換行以及任何其他字符。""" println("hello world!")""" 。另可默認 | 作為邊界前綴。
var text = """
    for (c in "foo") 
        print(c)
"""

// 去除前導空格
var text = """
  |Tell me and I forget.
  | Teach me and I remember.
""".trimMargin() 
字符串模板
  • 字符串字面值 可使用 模板表達式,以 美元符 $ 開頭。
  • 單個變量,可省略花括號,如 i ;表達式,則使用{a + b} 。

整理導入如下:


Kotlin 基本類型匯總

三、控制流

同 Java 有些差別,Kotlin 控制類分為:

  • if
  • when
  • for
  • while

以下僅整理不一致的點。

if 表達式
  • 若為單個 if 表達式,則可以直接 返回值或 賦值給變量,但必須要有 else 分支。
val max = if (a > b) a else b
when 表達式
  • 取代了 C 語言的 switch 語句。
  • 分支條件,可以是單個變量,也可以是 某個表達式,只要滿足條件,則執(zhí)行該分支的內(nèi)容。
  • 若 多個分支 處理方式一致,則可以將分支條件放在一起,用 , 隔開。
val x = 3
when (x) {
      1           -> print("x == 1")
      2,3         -> print("x > 1")
      "1".toInt() -> print("it's 1")
      in 1..10    -> print("x is in the range")
      !in 10..20  -> print("x is outside the range")
      is Int      -> print("x is Int type")
      else        -> print("none of above")
}
Break 與 Continue 標簽
  • Kotlin 中任何表達式都可以使用 標簽 來標記。標簽的格式:@標識符。
  • 函數(shù)嵌套,可返回到指定標簽處。

四、習慣用法

五、編碼規(guī)范

六、DEMO 練習

首先寫一個 Java Demo,然后對比一下 Kotlin 的寫法。具體內(nèi)容為:一個 User Model 類,一個 UserManager 單例類,再加上 main() 入口函數(shù)調(diào)用(均是內(nèi)部靜態(tài)類寫法)。

這里面涉及到關(guān)于 kotlin 的內(nèi)容點:

  • 變量聲明
  • 函數(shù)聲明
  • 空值與 null 檢測
  • 類與對象
  • 單例類
  • 靜態(tài)方法

這是我之前學 kotlin 時,特別想知道如果 kt 來寫,會是怎樣的。當然對于 static 修飾的變量和方法,在 kt 中都是包裹在 compion object 中,稱為「伴生對象」,這一點首次接觸,感覺非常新奇。

以下為 Java 實現(xiàn):

public class JavaDemo {

    public static void main(String[] args) {
        User user = new User();
        user.name = "cc";
        user.age = 24;
        user.address = "Shanghai";

        UserManager.getInstance().addUser(user);
        UserManager.getInstance().addUser(new User("kk", 25));
    }

    public static class UserManager {

        private static UserManager sInstance;

        private List<User> users = new ArrayList<>();

        public static UserManager getInstance() {
            if (sInstance == null) {
                synchronized(UserManager.class) {
                    if (sInstance == null) {
                        sInstance = new UserManager();
                    }
                }
            }
            return sInstance;
        }

        private UserManager() {}

        public void addUser(User user) {
            if (!users.contains(user)) {
                users.add(user);
            }
        }

        public void addUsers(List<User> users) {
            if (!this.users.containsAll(users)) {
                this.users.addAll(users);
            }
        }

        public void removeUser(User user) {
            users.remove(user);
        }

        public void removeByIndex(int index) {
            users.remove(index);
        }

        public void clear() {
            users.clear();
        }
    }

    public static class User {
        private String name;

        private int age;

        private String address;

        public User() {}

        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }
    }
}

Kotlin 寫法如下:

import java.util.*

class JavaVSKotlinDemo {

    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val user = User()
            user.name = "cc"
            user.age = 24
            user.address = "Shanghai"

            UserManager.getInstance().addUser(user)
            UserManager.getInstance().addUser(User("kk", 25))
        }
    }

    class UserManager private constructor() {

        private val users = ArrayList<User>()

        fun addUser(user: User) {
            if (!users.contains(user)) {
                users.add(user)
            }
        }

        fun addUsers(users: List<User>) {
            if (!this.users.containsAll(users)) {
                this.users.addAll(users)
            }
        }

        fun removeUser(user: User) {
            users.remove(user)
        }

        fun removeByIndex(index: Int) {
            users.removeAt(index)
        }

        fun clear() {
            users.clear()
        }

        companion object {
            // 單例模式
            private var sInstance: UserManager? = null
                get() {
                    return field ?: UserManager()
                }

            @JvmStatic
            @Synchronized
            fun getInstance(): UserManager {
                // synchronized(UserManager::class.java)
                return requireNotNull(sInstance)
            }
        }
    }
                                                                     
    class User constructor() {
        var name: String? = null

        var age: Int = 0

        var address: String? = null

        constructor(name: String?, age: Int) : this() {
            this.name = name
            this.age = age
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容