Android:Kotlin語法基礎

主函數

fun main(args: Array<String>){
    println("Hello World")
}
複製代碼

變量

一、常量html

val修飾常量,編譯器規定常量必須初始化,若不想初始化,可用**by lazy{}**對常量進行懶加載java

val a: Int = 1                     // 強類型常量
val b = 2                          // 弱類型常量
const val c = "Hello"              // 編譯器常量
val a: String by lazy{"lazy init"} // 懶加載常量
複製代碼

二、變量android

var修飾變量,編譯器規定變量必須初始化,若不想初始化,可用lateinit關鍵字限制報錯數組

lateinit var a                       //未初始化變量

var x = 5                            //初始化變量
var x1 = "x is $x"                   //獲取變量的值:$變量 
var x2 = "${x1.replace("is","was")}" //內嵌表達式:${表達式}

var str = """ //段落 <html> <a href="">go</a> </html> """
複製代碼

三、空值檢測安全

println(value?.size)                //if not null
println(value?.size ?: "empty")     //if not null and else
println(value.firstOrNull() ?: "")  //if not null and get first 
println(values["key"] ?: a + b)     //if not null and else + 表達式
value?.let{ }                       //if not null + 代碼塊
value!!.let{ }                      //告訴編譯器不須要判空
複製代碼

四、字符串比較bash

==:在kt中至關於java的equals() ===:在kt中至關於java的==閉包

數組

一、定義app

//每種基本類型都有對應的數組建立方法,相似於定製版
var array:IntArray = intArrayOf(1,3,5,7)
var array:CharArray = charArrayOf('H','E','L','L','O')
//基於泛性的建立方法,泛型也可省略,相似於通用版
var array:Array<Char> = arrayOf('H','E','L','L','O')
複製代碼

二、數組和字符串轉換ide

//第一種形式
var array:Array<Char> = arrayOf('H','E','L','L','O')
println(array.joinInString(""))
//第二種形式
var array:CharArray = charArrayOf('H','E','L','L','O')
println(String(array))
複製代碼

三、數組遍歷函數

var array:Array<Char> = arrayOf('H','E','L','L','O')
//第一種形式
array.forEach{println(it)}
//第二種形式
array.forEach{::println}
//第三種形式
for((index,value) in array.withIndex()){
    println("$index -> $value")
}
複製代碼

函數

一、有返回值的函數

//第一種形式
fun sum(a: Int, b: Int): Int {return a + b}
//第二種形式
fun sum(a: Int, b: Int) = return a + b
//第三種形式
fun sum(a: Int, b: Int) = a + b
複製代碼

二、無返回值的函數

Unit類型至關於Void類型,Unit返回類型能夠省略不寫

fun printSum(a: Int, b: Int): Unit { …… }
複製代碼

三、默認參數的函數

fun foo(a: Int = 0, b: String = "") { …… }
複製代碼

四、變長參數的函數

變長參數由vararg關鍵字決定,數組參數可經過*方式傳參,第一個參數能夠不使用名字指定,最後個參數必須使用具名參數

fun say(double: Double,vararg ints: Int,string: String) { …… }

val array = intArrayOf(1,3,4,5)
say(2.0,*array,string = "Hi")
複製代碼

五、擴展函數

你能夠給父類添加一個方法,這個方法將能夠在全部子類中使用

fun Activity.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(this, message, duration).show()
}
複製代碼

六、智能類型推測

判斷一個對象是否爲一個類的實例,可使用is關鍵字與Java中的instanceof關鍵字相似,但在Kotlin中若是已經肯定了一個對象的類型,能夠在接下來的代碼塊中直接做爲這個肯定類型使用

fun getStringLength(obj: Any): Int? {
  if (obj is String) {return obj.length}   //類型判斷後,obj會被系統自動轉換爲String類型
  if (obj !is String){}                    //同時還可使用!is,來取反
  return null                              //代碼塊外部的obj仍然是Any類型的引用
}
複製代碼

七、複合函數

複合函數指的是函數中存在另外一個函數,相似於數學的f(g(x))

infix fun <P1,P2,R> Function1<P1,P2>.andThen(function: Function1<P2,R>): Function1<P1,R>{
    return fun(p1:P1): R{
        return function.invoke(this.invoke(p1))
    }
}

var add = {i: Int -> i + 5}
var plus = {i: Int -> i * 2}
var addAndPlus = add andThen plus
println(addAndPlus(8))  // (8+5)*2=26
複製代碼

八、函數的科理化

函數的科理化指的是函數中傳遞的多個參數可轉換爲多個函數來進行連接

//科理化前的函數
fun log(tag: String,target: OutputStream,message: Any?){
    target.write("$tag $message\n".toByteArray())
}
log("Hensen",System.out,"HelloWorld")

//科理化後的函數
fun log(tag: String)
    = fun(target: OutputStream)
    = fun(message: Any?)
    = target.write("$tag $message\n".toByteArray())
log("Hensen")(System.out)("HelloWorld")
複製代碼

Lambda表達式

一、定義Lambda表達式

var sum = {arg1: Int,arg2: Int ->
    arg1 + arg2
}
//使用第一種方式
sum(1,2)
//使用第二種方式
sum.invoke(1,2)
複製代碼

二、帶有return的Lambda表達式

Lambda表達式並非函數,若是直接return,會退出當前調用Lambda表達式的函數,而不是退出當前的Lambda表達式,可使用**@別名**的方式退出

var array:Array<Char> = arrayOf('H','E','L','L','O')
array.forEach ForEach@{
    if(it == 'L')return@ForEach
    println(it)
}
複製代碼

三、帶有run的Lambda表達式

調用某對象的run函數,在函數塊內能夠經過this指代該對象。返回值爲函數塊的最後一行或指定return表達式

val a = "string".run {
    print(this) //string
    3
}
println(a) //3
複製代碼

四、帶有let的Lambda表達式

調用某對象的let函數,則該對象爲函數的參數。在函數塊內能夠經過it指代該對象。返回值爲函數塊的最後一行或指定return表達式

val a = "string".let {
    println(it) //string
    3
}
println(a) //3
複製代碼

五、帶有with的Lambda表達式

它是將某對象做爲函數的參數,在函數塊內能夠經過this指代該對象。返回值爲函數塊的最後一行或指定return表達式

val a = with("string") {
    println(this) //string
    3
}
println(a) //3
複製代碼

六、帶有apply的Lambda表達式

調用某對象的apply函數,在函數塊內能夠經過this指代該對象。返回值爲該對象本身

val a = "string".apply {
    println(this) //string
}
println(a) //string
複製代碼

七、帶有also的Lambda表達式

調用某對象的also函數,則該對象爲函數的參數。在函數塊內能夠經過it指代該對象。返回值爲該對象本身

val a = "string".also {
    println(it) //string
}
println(a) //string
複製代碼

八、小結

  • run:使用this指定當前對象,最後一行爲返回值
  • let:使用it指定當前對象,最後一行爲返回值
  • with:使用this指定當前對象,最後一行爲返回值,寫法上有區別
  • apply:使用this指定當前對象,返回值爲該對象本身
  • also:使用it指定當前對象,返回值爲該對象本身

表達式

一、When表達式

fun transform(x: Int){
    return when (x) {
        is Int -> println("$x is Int")
        in 1..100 -> println("$x is in 1-100")
        !in 1..100 -> println("$x is not in 1-100")
        //else不寫則不作默認操做
        else -> throw IllegalArgumentException("Invalid x param value")
    }
}
複製代碼

或者

fun describe(obj: Any): String =
    when (obj) {
        1          -> "One"
        "Hello"    -> "Greeting"
        is Long    -> "Long"
        !is String -> "Not a string"
        else       -> "Unknown"
}
複製代碼

二、try-catch表達式

fun test() {
    val result = try {
        count()
    } catch (e: ArithmeticException) {
        throw IllegalStateException(e)
    }
}
複製代碼

三、if表達式

fun foo(param: Int) {
    val result = if (param == 1) {
        "one"
    } else if (param == 2) {
        "two"
    } else {
        "three"
    }
}
複製代碼

四、with表達式

class Turtle {
    fun penDown()
    fun penUp()
    fun turn(degrees: Double)
    fun forward(pixels: Double)
}

val myTurtle = Turtle()
with(myTurtle) { // 畫一個 100 像素的正方形
    penDown()
    for(i in 1..4) {
        forward(100.0)
        turn(90.0)
    }
    penUp()
}
複製代碼

五、for表達式

val items = listOf("apple", "banana", "kiwifruit")
for (item in items) {
    println(item)
}

val items = listOf("apple", "banana", "kiwifruit")
for (index in items.indices) {
    println("item at $index is ${items[index]}")
}
複製代碼

六、while表達式

val items = listOf("apple", "banana", "kiwifruit")
var index = 0
while (index < items.size) {
    println("item at $index is ${items[index]}")
    index++
}
複製代碼

七、中綴表達式

使用infix關鍵字建立中綴表達式

Class Book{
    infix fun on(any: Any): Boolean{
        return false
    }
}

Class Desk{
    
}

if(Book on Desk){
   println("book on the desk") 
}
複製代碼

閉包

一、函數內部能夠定義函數,屬於閉包

fun add(x: Int): (Int)-> Int{
    return fun(y: Int): Int{
        return x + y
    }
}
複製代碼

二、閉包持有函數內部的運行狀態

fun justCount():() -> Unit{
    var count = 0 //被函數內部持有
    return {
        println(count++)
    }
}

fun main(args: Array<String>) {
    val count = justCount()
    count()  // 輸出結果:0
    count()  // 輸出結果:1
    count()  // 輸出結果:2
}
複製代碼

三、自行閉包

自執行閉包就是在定義閉包的同時直接執行閉包,通常用於初始化上下文環境

{ x: Int, y: Int ->
    println("${x + y}")
}(1, 3)
複製代碼

運算符

一、自定義運算符

class Complex(var arg1: Double,var arg2: Double){
    operator fun plus(other: Complex): Complex{
        return Complex(arg1 + other.arg1,arg2 + other.arg2)
    }
    
    operator fun plus(other: Int): Complex{
        return Complex(arg1 + other,arg2)
    }
    
    oprator fun invoke(): Double{
        return Math.hypot(arg1,arg2)
    }
    
    overide fun toString(): String{
        return "${arg1} and ${arg2}"
    }
}

val c1 = Complex(3.0,4.0)
val c1 = Complex(2.0,5.0)
println(c1 + c2) //5.0 and 9.0
println(c1 + 5) //8.0 and 4.0 
println(c1()) //5
複製代碼

區間語句

一、定義區間

var range = 0..1024 //[0,1024]閉區間
var range = 0 until 1024 //[0,1024)半開區間
var range = 0..-1 //空區間
複製代碼

二、檢查x是否在指定區間裏面

val x = 10
val y = 9
if (x in 1..y+1) {
    println("fits in range")
}
複製代碼

三、檢查list.size是否在list的索引上

val list = listOf("a", "b", "c")

if (-1 !in 0..list.lastIndex) {
    println("-1 is out of range")
}
if (list.size !in list.indices) {
    println("list size is out of valid list indices range too")
}
複製代碼

四、區間遍歷

for (x in 1..10 step 2) {
    print(x) //13579
}
for (x in 9 downTo 0 step 3) {
    print(x) //9630
}
複製代碼

集合

一、初始化

val mutableList = mutableListOf(0, 1)   //可讀寫List對象
var list = listOf(0, 1, 2)              //可讀List對象
val set = setOf(1, 2, 4)                //可讀Set對象
複製代碼

二、集合遍歷

val items = listOf("a", "b", "c")
for (item in items) {
    println(item)
}
複製代碼

三、集合判斷

val items = listOf("apple", "balanace", "coffee")
when {
    "orange" in items -> println("juicy")
    "apple" in items -> println("apple is fine too")
}
複製代碼

映射

一、初始化

val map = mutableMapOf("a" to 1, "b" to 2, "c" to 3) //可讀寫Map對象
val map = mapOf("a" to 1, "b" to 2, "c" to 3)        //可讀Map對象
複製代碼

二、訪問Map

map["key"] = value
複製代碼

三、遍歷Map

for ((k, v) in map) {
    println("$k -> $v")
}
複製代碼

構造方法

一、主構造函數

Kotlin的構造函數能夠寫在類頭中,跟在類名後面,若是有註解還須要加上關鍵字constructor

class Person(private val name: String) {

    fun sayHello() {
        println("hello $name")
    }
}
複製代碼

在主構造函數中不能有任何代碼實現,若是有額外的代碼須要在構造方法中執行,你須要放到init代碼塊中執行

class Person(private var name: String) {
	
    init {
        name = "Zhang Tao"
    }

    fun sayHello() {
        println("hello $name")
    }
}
複製代碼

二、次構造函數

存在兩個或兩個以上的構造方法時,能夠增長次構造方法

class Person(private var name: String) {

    private var description: String? = null
    
    init {
        name = "Zhang Tao"
    }

    constructor(name: String, description: String) : this(name) {
        this.description = description
    }
    
    fun sayHello() {
        println("hello $name")
    }
}
複製代碼

類與對象

一、輸出類名

println(HelloWorld::class.java.simpleName) //輸出類名
println(HelloWorld::class.java.name) //輸出包名+類名
複製代碼

二、建立對象

val rectangle = Rectangle(5.0, 2.0)
val triangle = Triangle(3.0, 4.0, 5.0)
複製代碼

三、數據類

data修飾的類稱之爲數據類,當data修飾後,會自動將全部成員用operator聲明,即爲這些成員生成getter()和setter()

data class Customer(val name: String, val email: String)
複製代碼

編譯器自動從主構造函數中的屬性導入下面這些成員函數

equals()
hashCode()
toString()
componentN():函數返回對應着聲明的參數順序
copy()
複製代碼

四、內部類

Kt默認的內部類爲靜態內部類,可使用inner關鍵字將內部類變爲非靜態內部類,且可以使用註解去獲取外部類的成員屬性

class Outter{
    var a = 5
    inner class Inner{
        var a = 6
        fun getOutterA(){
            println(this@Outter.a)
        }
    }
}
複製代碼

五、單例類

object關鍵字表示該類是單例

class Single private constructor() {
    companion object {
        fun get():Single{
            return Holder.instance
        }
    }

    private object Holder {
        val instance = Single()
    }
}
複製代碼

或者

object Resource {
    val name = "Name"
}
//使用
Resource.INSTANCE.name
複製代碼

六、枚舉類

枚舉默認沒有數值,若是須要固定類型的數值,可在類名後聲明參數類型

enum class Programer(val id: Int) {
    JAVA(0), KOTLIN(1), C(2), CPP(3), ANDROID(4);
    fun getTag(): String{
        return "$id + $name"
    }
}
//使用
println(Programer.JAVA.getTag())
複製代碼

七、密封類

sealed修飾的類稱爲密封類,用來表示受限的類層次結構

sealed class BaseClass {
    class Test1 : BaseClass() {
        override fun test() {
            println("Test1實例")
        }

    }
    class Test2 : BaseClass() {
        override fun test() {
            println("Test2實例")
        }
    }
    object Test3 : BaseClass() {
        override fun test() {
            println("Test3實例")
        }
    }
    open fun test() {
        println("BaseClass實例")
    }
}
複製代碼

密封類與枚舉的區別:

密封類是枚舉類的擴展 枚舉類型的值集合是受限的,且每一個枚舉常量只存在一個實例 密封類的一個子類能夠有可包含狀態的多個實例 八、繼承

在class中加open關鍵字便可被繼承

open class Person(var name:String, var age:Int){
    
}
複製代碼

九、接口代理

接口代理表示代理人可直接調用接口代理的方法

//代理driver和writer,當執行manager.driver(),Manager類會去調用代理的driver.driver()
class Manager(val driver: Driver,val writer: Writer):Driver by driver,Writer by writer

interface Driver{fun driver()}
interface Wirter{fun wirter()}
複製代碼

十、伴生對象

companion關鍵字修飾對象內的方法,咱們稱companion修飾的對象爲伴生對象,本質是靜態方法。若是在Java文件中想經過類名的方式去調用靜態方法,則須要加入註解纔可使用

class StringUtils {
    companion object {
        @JvmStatic
        fun isEmpty(str: String): Boolean {
	        return "" == str
	    }
	    @JvmField
	    var TAG = "StringUtils"
    }
}
複製代碼

十一、方法重載

因爲Kt中有默認參數的性質,因此方法的重載能夠用默認參數來實現,若是在Java文件中想使用Kt重載的話,就須要加入註解纔可使用

class StringUtils {
    @JvmOverloads
    fun a(int: Int = 0): Int{
        return int
    }
}
複製代碼

十二、匿名對象

使用object對象表示匿名對象

btn?.setOnClickListener(object : View.OnClickListener{
    override fun onClick(v: View?) {
    
    }
})
複製代碼

經常使用操做符

Kotlin的操做符跟RxJava基本一致

一、下標操做類

  • contains:判斷是否有指定元素
  • elementAt:返回對應的元素,越界會拋IndexOutOfBoundsException
  • firstOrNull:返回符合條件的第一個元素,沒有返回null
  • lastOrNull:返回符合條件的最後一個元素,沒有返回null
  • indexOf:返回指定元素的下標,沒有 返回-1
  • singleOrNull:返回符合條件的單個元素,若有沒有符合或超過一個,返回null

二、判斷類

  • any:判斷集合中 是否有知足條件的元素
  • all:判斷集合中的元素是否都知足條件
  • none:判斷集合中是否都不知足條件,是則返回true
  • count:查詢集合中知足條件的元素個數
  • reduce:從第一項到最後一項進行累計

三、過濾類

  • filter:過濾 掉全部知足條件的元素
  • filterNot:過濾全部不知足條件的元素
  • filterNotNull:過濾NULL
  • take:返回前n個元素

四、轉換類

  • map:轉換成另外一個集合
  • mapIndexed:除了轉換成另外一個集合,還能夠拿到Index
  • mapNotNull:執行轉換前過濾掉 爲 NULL 的元素
  • flatMap:自定義邏輯合併兩個集合
  • groupBy:按照某個條件分組,返回Map

五、排序類

  • reversed:反序
  • sorted:升序
  • sortedBy:自定義排序
  • sortedDescending:降序

六、實戰操做符

val fruits = listOf("banana", "avocado", "apple", "kiwifruit")
fruits
  .filter { it.startsWith("a") }
  .sortedBy { it }
  .map { it.toUpperCase() }
  .forEach { println(it) }
複製代碼

特性

一、懶加載

val p: String by lazy {
    // 計算該字符串
}
複製代碼

二、安全類型轉換

父類轉成子類會拋出類型轉換失敗的錯誤,若是採用**as?**的方式,則返回null

var child: Child = parent as? Child
複製代碼

三、輸出可執行文件

在Gradle添加依賴指定main函數文件,後綴名爲Kt

apply plugin:'application'
mainClassName = "com.hensen.android.MyCalcKt"
複製代碼

刷新Gradle,在Gradle右邊欄點擊distribution/installDist,生成的程序在build/install目錄下

四、internal關鍵字

在變量中使用internal關鍵字表示成員變量只容許在模塊內能被訪問到

internal var name
複製代碼

五、尾遞歸

對於遞歸函數,若是遞歸函數並未對遞歸的結果進行操做,則可使用tailrec關鍵字將遞歸聲明爲尾遞歸,尾遞歸會優化代碼,將遞歸轉換成迭代

data class ListNode(val value: Int,var next: ListNode?)
//對遞歸的結果並未操做,屬於尾遞歸
tailrec fun findListNode(head: ListNode?,value: Int): ListNode?{
    head?: return null
    if(head.value == value) return head
    return findListNode(head.next,value)
}
//對遞歸的結果進行乘法運算,不屬於尾遞歸
fun factorial(n: Long): Long{
    return n * factorial(n - 1)
}
複製代碼

Android相關

一、view.find

使用Ktolin的拓展函數,view.find替代findViewById

var textView = view.find(R.id.textView)
複製代碼

二、observable

Delegates.observable能夠監聽當前的變量值的變化,改變變量的值,便可觸發observable

private var mCurrentState: Int by Delegates.observable(-1) { _, old, new ->
    if (old != new) {
        RxBus.getDefault().post(ChannelPK_OnModelChange_Rank_EventArgs(new == 1))
        MLog.info(PKModelManager.TAG, "rank mode : $old -> $new")
    }
}

fun onModelChange() {
    mCurrentState = 1 //改變變量的值,便可觸發observable
}
複製代碼

三、bundle

建立bundle已經不須要再去執行其各類put方法

val bundle = bundleOf(
        "KET_INT" to 1,
        "KET_LONG" to 2L,
        "KET_BOOLEAN" to true,
        "KEY_NULL" to null,
        "KEY_ARRAY" to arrayOf(1, 2)
)
複製代碼

四、Parcelize

Parcelize已經不須要再寫什麼代碼了,只須要繼承和註解

@Parcelize
data class User(val name: String,val age: Int): Parcelize
複製代碼
@Parcelize的使用須要在gradle聲明變量

androidExtensions {
    experimental = true
}
複製代碼

五、Serializable

指定Serializable的名字

class Book(@SerializedName(TXT) var txt: String)
複製代碼

六、postDelay

postDelay支持閉包和lambda表達式

handler.postDelayed(50) {
    // lambda
}
複製代碼

七、註解

若是說在Java文件中須要使用到KT的變量、靜態方法、重載方法等,就須要註解聲明

  • @JvmField:將屬性編譯爲Java變量
  • @JvmStatic:將伴生對象編譯爲Java靜態方法
  • @JvmOverloads:默認參數生成重載方法
  • @file:JvmName:指定Kotlin文件編譯後的類名
相關文章
相關標籤/搜索