前言
上節我們主要講了Kotlin的數據類型,這節我們主要從程序結構,包括方法,類成員,運算符的角度去認識Kotlin
常量與變量
上一節我們已經用到了用val,var來修飾屬性。這節我們詳細總結下:
- 常量(val)
- val=value,值類型
- 類似Java的final
- 不可能重複賦值
- 運行時常量: val x = getX()
- 編譯期常量: const val x=2
Java final是運行時常量 Kotlin是編譯器常量 例子:
Java:
public final String S1="A"
public String s2=S1
運行時字節碼:
public s2="A" //直接指向值 而不是變量名
Kotlin:
val S1:String="A"
var s2:String =S1
運行時字節碼:
static{
s2=S1//這裏沒有直接指向S1的值 所以是編譯期常量
}
-
變量(var)
- var = variable
- var x =“HelloWorld”//定義變量
- x =“HiWorl”//再次賦值
-
類型推導
編譯器可以推導量的類型- val string =“Hello"//推導出String類型
- valint=5IIInt類型
- var x = getString() + 5 //String類型
函數
函數是以特定功能組織起來的代碼塊
舉例:
- fun sayHi(name: String){ println(“Hi, $name”) }
- fun sayHi(name: String) = println(“Hi, $name")
- 匿名函數
- fun([參數列表])): [返回值類型]{ [函數體] }
- 舉例:- val sayHi = fun(name: String) = println(“Hi, $name")
- fun([參數列表])): [返回值類型]{ [函數體] }
Java是面向對象的,Kotlin是面向函數的,函數是一等公民,是在Java中你可以將調用一個對象,也可以將一個對象傳來傳去,在Kotlin中函數也是可以的做到像Java對象一樣,下面結合代碼來體驗一下
fun main(args: Array<String>) {
//不建議這麼去寫 這麼寫 是無法區分你想調用的是常量還是函數
//這裏和重載也不相同 因爲val sum =fun 後面接的是無方法名的方法
//這裏默認是調用的方法 如果想調用常量方法 可以使用sum.invoke()等價於 sum()
println("方法函數 " + sum(args[0].toInt(), args[1].toInt()))
println("方法函數 invoke: " + sum(args[0].toInt(), args[1].toInt()))
println("常量" + sum.invoke(args[0].toInt(), args[1].toInt()))
}
fun sum(aInt1: Int, aInt2: Int): Int {
return aInt1 + aInt2
}
val sum = fun(aInt1: Int, aInt2: Int): Int {
println("$aInt1 + $aInt2 = ${sum(aInt1, aInt2)}")
return aInt1 + aInt2
}
fun printlnUarge(): String {
return "請輸入兩個數值 例: 1 2"
}
val uager = fun(): String {
return "請輸入兩個數值 例: 1 2"
}
Lambda表達式
Lambda 允許把函數作爲一個方法的參數(函數作爲參數傳遞進方法中)。
使用 Lambda 表達式可以使代碼變的更加簡潔緊湊。
Java1.8加入,Kotlin作爲面向函數編程的語言,他一出生就完美支持lambda
- 語法
(parameters) -> expression
或
(parameters) ->{ statements; }
-
lambda表達式的重要特徵
- 可選類型聲明:不需要聲明參數類型,編譯器可以統一識別參數值。
- 可選的參數圓括號:一個參數無需定義圓括號,但多個參數需要定義圓括號。
- 可選的大括號:如果主體包含了一個語句,就不需要使用大括號。
- 可選的返回關鍵字:如果主體只有一個表達式返回值則編譯器會自動返回值,大括號需要指定明表達式返回了一個數值。
簡單例子:
// 1. 不需要參數,返回值爲 5
() -> 5
// 2. 接收一個參數(數字類型),返回其2倍的值
x -> 2 * x
// 3. 接受2個參數(數字),並返回他們的差值
(x, y) -> x – y
// 4. 接收2個int型整數,返回他們的和
(int x, int y) -> x + y
// 5. 接受一個 string 對象,並在控制檯打印,不返回任何值(看起來像是返回void在Kotlin中時Unit)
(String s) -> System.out.print(s)
Lambda表達式要是細說的話可能一篇文章也不夠,我覺得剛開始看雖然代碼變的更簡潔,但是對我我這種只會Java一種語言的來說一下子轉變有時候還是挺彆扭的,感覺這個就得多寫多看慢慢適應。
這裏我再結合前面講的函數和Kotlin特性寫幾個例子:
fun multiply_1(arg1: Int, arg2: Int): Int {//具名函數 Lambda: (Int,Int)->Int
return arg1 * arg2
}
fun multiply_2(arg1: Int, arg2: Int) = arg1 * arg2//具名函數 Lambda: (Int,Int)->Int
val multiply_3 = { arg1: Int, arg2: Int -> arg1 * arg2 }//匿名函數 Lambda: (Int,Int)->Int
val multiply_4 = { arg1: Int, arg2: Int ->
//lambda
println("HelloWorld multiply_4")
println("HelloWorld multiply_4")
println("HelloWorld multiply_4")
arg1 * arg2//最後一行作爲lambda的返回值
}
val multiply_5 = fun(arg1: Int, arg2: Int): Int {
return arg1 * arg2
}//匿名函數 Lambda: (Int,Int)->Int
val multiply_6 = {//匿名函數 Lambda: ()->Unit
//lambda
println("HelloWorld")
}
fun printlnUsage() {//具名函數 Lambda: ()->Unit
println("no return element")
}
//匿名函數 Lambda: ()->Unit
val sum1 = { it: String ->
println(it)//方法體內容
Unit//最後一行作爲lambda的返回值 Kotlin Unit相當於Java的Void無返回值
}
這幾個例子應該覆蓋了我們會用到的大部分例子的類比了。
- 循環語句
Kotlin的循環語句有些特殊看下面的例子:
//args=a b c d e f
fun main(args: Array<String>) {
for (i in args) {
println(i)
}
args.forEach{
if (it == "d") return
println(it)
}
println("The End")
}
當調用第二種循環,如果如上想跳出循環,那麼println(“The End”)這句並不會執行。因爲 {}中的內容是表達式而不是函數,所以return的是main這個函數,可以改成如下:
run Break@/*外部標識*/{
args.forEach Continue@/*內部標識*/{
if (it == "d") return@Continue
println(it)
}
}
println("The End")
添加標識,return@Continue相當於java的Continuereturn@Break相當於Java的break。(這裏標識的定義是隨便寫的,@A @ABC都可以)
成員方法和成員變量
這部分比較簡單直接舉例子:
class X
class B {
// lateinit var a:Int //錯誤 不能再原始類型中使用 lateinit
// lateinit var a:Double//error
// lateinit var a1:Long//error
// lateinit var a2:Float//error
// lateinit var a3:Short//error
// lateinit var a4:Char//error
// lateinit var a5:Byte//error
// lateinit var b: Boolean//error
var a: Int = 0
get() = field//默認可以不寫
set(value) {//默認可以不寫
field = value
}
lateinit var c: String
lateinit var x1: X
// lateinit val x2: //錯誤 不可以 val 類似final 定義後別虛初始化
val x2: X by lazy {
X()
}
var cc: String? = null
fun value() {
}
}
fun main(args: Array<String>) {
val b = B()
b.value()
b.a
}
我們直接對上面的代碼進行總結:
- var/val a: Int = 0默認訪問修飾符是public,同時默認幫我們getter和setter,當然我們也可以重寫這兩個方法
- field這個屬性(也叫Backing Field)只能在getter和setter才能訪問到,更多詳見理解Backing Field
- Kotlin建議val/var修飾的屬性最好直接初始化或是在構造方法中初始化,如果不可以就降級爲局部變量**
- lateinit延時初始化,不可以修飾val,不可以修飾基本數據類型(因爲基本數據類型有默認值),理智使用lateinit否則會空指針
- by lazy{} 可以修飾val
結語
篇幅不宜過長,下篇繼續說說程序結構