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