kotlin使用記錄

https://kotlinlang.org/docs/reference/android-overview.html
學(xué)習(xí)資料

github>>kotlin
courses/

中文入門語法

記錄

let, also,apply,run

https://blog.csdn.net/u013064109/article/details/78786646
簡(jiǎn)單分析下,also和apply一樣都是返回自己, let和run一樣返回花括號(hào)代碼塊最后一行的返回值
另外一樣的2種區(qū)別就在于代碼塊里用it還是this代替變量,而this可以省略不寫。

image.png

如上圖,結(jié)果就是 2個(gè)hello,以及7和5
簡(jiǎn)單看下源碼

public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
public inline fun <T> T.also(block: (T) -> Unit): T { block(this); return this }

public inline fun <T, R> T.let(block: (T) -> R): R = block(this)
public inline fun <T, R> T.run(block: T.() -> R): R = block()

看到源碼可能感覺和我們的寫法不一樣。其實(shí)原因很簡(jiǎn)單,kotlin里一個(gè)函數(shù)可以作為參數(shù)的,完事這個(gè)函數(shù)可以寫到括號(hào)外邊。
比如 T.apply({//函數(shù)塊}) 可以寫成 T.apply(){//函數(shù)塊}
對(duì)于let和run,如果要主動(dòng)return一個(gè)東西,這樣寫的// return@run 333

在看demo的時(shí)候看到這些代碼,擴(kuò)展函數(shù)

可以注意到方法名字前有個(gè)xxx. 的東西,這個(gè)就是聲明對(duì)哪個(gè)類進(jìn)行擴(kuò)展

/**
 * The `fragment` is added to the container view with id `frameId`. The operation is
 * performed by the `fragmentManager`.
 */
fun AppCompatActivity.replaceFragmentInActivity(fragment: Fragment, @IdRes frameId: Int) {
    supportFragmentManager.transact {
        replace(frameId, fragment)
    }
}

/**
 * The `fragment` is added to the container view with tag. The operation is
 * performed by the `fragmentManager`.
 */
fun AppCompatActivity.addFragmentToActivity(fragment: Fragment, tag: String) {
    supportFragmentManager.transact {
        add(fragment, tag)
    }
}

fun AppCompatActivity.setupActionBar(@IdRes toolbarId: Int, action: ActionBar.() -> Unit) {
    setSupportActionBar(findViewById(toolbarId))
    supportActionBar?.run {
        action()
    }
}

/**
 * Runs a FragmentTransaction, then calls commit().
 */
private inline fun FragmentManager.transact(action: FragmentTransaction.() -> Unit) {
    beginTransaction().apply {
        action()
    }.commit()
}

代碼里這樣用的

        setupActionBar(R.id.toolbar) {
            setHomeAsUpIndicator(R.drawable.ic_menu)
            setDisplayHomeAsUpEnabled(true)
        }

其實(shí)原本應(yīng)該這樣的,不過最后一個(gè)參數(shù)是一個(gè)函數(shù)的話,可以直接把括號(hào)的實(shí)現(xiàn)提到圓括號(hào)外面,就成了上邊的寫法了

        setupActionBar(R.id.toolbar, {
            setHomeAsUpIndicator(R.drawable.ic_menu)
            setDisplayHomeAsUpEnabled(true)
        })

when

java 中的switch 在kotlin里的寫法,

when(xxx){
            is Int->{
            }
            in 0..10->{
            }
 1->{
}
2->{
}
3,4->{}
else->{}
}

2個(gè)方法互相引用的時(shí)候

java代碼如下,我是2個(gè)runnable 互相調(diào)用

    private void starte(){
        handler.postDelayed(r1,1000);
    }
    Handler handler=new Handler();
    
    Runnable r1=new Runnable() {
        @Override
        public void run() {
            System.out.println("==========1");
            handler.postDelayed(r2,1111);
        }
    };
    
    Runnable r2=new Runnable() {
        @Override
        public void run() {
            System.out.println("==========2");
            handler.postDelayed(r1,1111);      
        }
    };

kotlin代碼如下

    internal var handler = Handler()

    internal var r1: Runnable = Runnable {
        println("==========1")
        handler.postDelayed(r2, 1111)
    }

    internal var r2: Runnable = Runnable {
        println("==========2")
        handler.postDelayed(r1, 1111)
    }

    private fun starte() {
        handler.postDelayed(r1, 1000)
    }

看下轉(zhuǎn)化,加了internal,這個(gè)是限定同一模塊下可以訪問,非必需。
關(guān)鍵有的地方 r2: Runnable 這個(gè),2個(gè)Runnable必須有一個(gè)需要加冒號(hào)聲明類型,否則就報(bào)錯(cuò)。
Type checking has run into a recursive problem. Easiest workaround: specify types of your declarations explicitly
中文:類型檢查遇到了遞歸問題。最簡(jiǎn)單的解決方法:顯式地指定聲明的類型。

可以看到上邊都是簡(jiǎn)化后的寫法了。如果這個(gè)時(shí)候要使用this,就不行了,得寫完整的
如下

    internal var r2: Runnable = object : Runnable {
        override fun run() {
            println("==========2")
            handler.postDelayed(r1, 1111)
            handler.postDelayed(this, 2222)
            Runnable { handler.postDelayed(this, 2222) }.run()
        }
    }

循環(huán)的幾種寫法

下邊的代碼結(jié)果都一樣,都是從0到4循環(huán)的,從大到小的話可以用 downto關(guān)鍵字

    private fun forTest(){
        //循環(huán)N次,from 0 start
        repeat(5){
            println("a============$it")
        }
        for(i in 0 ..4){
            println("b==========$i")
        }
        for(i in 0 until 5){
            println("c==========$i")
        }
        (0..4).forEach {
            println("d==============$it")
        }
    }

set get

//set的簡(jiǎn)化寫法
     var tasks: List<Task> = tasks
            set(tasks) {
                field = tasks
                notifyDataSetChanged()
            }

  //get的簡(jiǎn)化寫法
    override var isActive: Boolean = false
        get() = isAdded

thread ,簡(jiǎn)化寫法如下,不需要start,內(nèi)部默認(rèn)構(gòu)造方法里start為true的。

thread {

}

問題記錄

1~
java 代碼 Object obj=new Object(); obj.wait();
kotlin里的Any()對(duì)象沒有wait()方法,不知道轉(zhuǎn)成kotlin之后咋寫。
解決辦法,kt里繼續(xù)new一個(gè)Object對(duì)象而不是any對(duì)象。
http://www.itdecent.cn/p/3963e64e7fe7
2~

雙冒號(hào)::

可以理解為把一個(gè)方法當(dāng)對(duì)象處理,如下

    class A {
       lateinit var b:B
        init {
            b=B().apply {
                this.callbackA=this@A::testA//把testA這個(gè)方法傳遞給B里邊的一個(gè)變量callbackA了
            }
        }
        fun testA(name: String,age:Int){

        }
    }
    class B{
        var callbackA:((String,Int) ->Unit)?=null//這里對(duì)應(yīng)寫出參數(shù)的類型,返回的類型好匹配,因?yàn)槭强梢詾榭盏?,所以括起來加個(gè)問號(hào)
        fun testB(){
            callbackA?.invoke("jerry",33)
        }
    }

上邊的可以用來寫我們平時(shí)用的Callback。
如果是java,我們一般是定義一個(gè)interface,完事定義一個(gè)interface的變量,然后用的時(shí)候?qū)嵗粋€(gè)interface調(diào)用
然后看下改版后的寫法
如下自定義的類

class ItemTouchListener{

//某個(gè)地方調(diào)用
singleTapCallback?.invoke(position,rv.getChildViewHolder(child))

//然后定義的回調(diào)
var singleTapCallback:((position: Int, viewHolder: RecyclerView.ViewHolder)->Unit)?=null
}

然后是正式使用的地方

        rv_temp.addOnItemTouchListener(ItemTouchListener(rv_temp).apply {
            singleTapCallback=this@FragmentTempTest::singleTab
//或者這樣調(diào)用也可以
            singleTapCallback={position, viewHolder -> 
                
            }
        })

//這個(gè)就是我們的回調(diào)實(shí)現(xiàn)方法拉。
   fun singleTab(position: Int, viewHolder: RecyclerView.ViewHolder){

    }

這里還有一些
https://blog.csdn.net/lmo28021080/article/details/81505211

inline,noline

參考https://blog.csdn.net/Jaden_hool/article/details/78437947

基本數(shù)據(jù)類型

比較坑的地方,就是不能互相自動(dòng)轉(zhuǎn)化,java里我們定義個(gè)float,傳個(gè)int也沒問題的,在kt里就不行
有點(diǎn),數(shù)字下邊可以加下劃線,看起來更直觀

val oneMillion = 1_000_000
val creditCardNumber = 1234_5678_9012_3456L
val socialSecurityNumber = 999_99_9999L
val hexBytes = 0xFF_EC_DE_5E
val bytes = 0b11010010_01101001_10010100_10010010
== === 2個(gè)等號(hào)和3個(gè)等號(hào)的區(qū)別

前者是數(shù)值比較,后者是地址比較
== 和 ===
其中這個(gè)比較嚇人

fun main(args: Array<String>) {
   val a: Int = 1000
   val b: Int? = a
   val c: Int? = a
   println(b == c)    //true
   println(b === c)   //false    
}


fun main(args: Array<String>) {
   val a: Int = 100
   val b: Int? = a
   val c: Int? = a
   println(b == c)    //true
   println(b === c)   //true    
}

兩段代碼除了a的初始值不一樣,其他都一樣,可結(jié)果3個(gè)等號(hào)的結(jié)果不一樣。
這個(gè)就是java里基本數(shù)據(jù)類型和對(duì)象的問題了,看下源碼,128以下的,用的是同一個(gè)對(duì)象,從緩存數(shù)組讀出來的,所以對(duì)象比較也是相等的,128以上的,就是每次new一個(gè)新的了,不是一個(gè)對(duì)象了。

    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
運(yùn)算符

這是完整的位運(yùn)算列表(只用于 Int 與 Long):

shl(bits) – 有符號(hào)左移 (Java 的 <<)
shr(bits) – 有符號(hào)右移 (Java 的 >>)
ushr(bits) – 無符號(hào)右移 (Java 的 >>>)
and(bits) – 位與
or(bits) – 位或
xor(bits) – 位異或
inv() – 位非

后綴 u 與 U 將字面值標(biāo)記為無符號(hào)

val l: ULong = 1u  // ULong,已提供預(yù)期類型

val a1 = 42u // UInt:未提供預(yù)期類型,常量適于 UInt
"""

原始字符串 使用三個(gè)引號(hào)(""")分界符括起來,內(nèi)部沒有轉(zhuǎn)義并且可以包含換行以及任何其他字符:
比如下邊這個(gè),最終顯示結(jié)果有4行,第一個(gè)換行,最后一行換行的,中間的空白頁都保留的

val text = """
    for (c in "foo")
        print(c)
"""
when

常見的when用法,類似java里的swtich,不過比這個(gè)強(qiáng)大很多

when (x) {
    parseInt(s) -> print("s encodes x")
   in 1..10 -> print("x is in the range")
    in validNumbers -> print("x is valid")
    !in 10..20 -> print("x is outside the range")
is String -> x.startsWith("prefix")
    else -> print("s does not encode x")
}

when 也可以用來取代 if-else if鏈。 如果不提供參數(shù),所有的分支條件都是簡(jiǎn)單的布爾表達(dá)式,而當(dāng)一個(gè)分支的條件為真時(shí)則執(zhí)行該分支:

when {
    x.isOdd() -> print("x is odd")
    x.isEven() -> print("x is even")
    else -> print("x is funny")
}

還有這種

fun Request.getBody() =
        when (val response = executeRequest()) {
            is Success -> response.body
            is HttpError -> throw HttpException(response.status)
        }
密封類

用sealed 修飾class
sealed

for

for的特殊用法,迭代類型的可以直接拿到key和value

        val arr= arrayListOf(2,3,3,33,3)
        for((index,value) in arr.withIndex()){
            
        }
標(biāo)簽lable

標(biāo)示符后邊加個(gè)@即可

loop@ for (i in 1..100) {
    // ……
}

函數(shù)

主構(gòu)造函數(shù)和次構(gòu)造函數(shù),還有init的執(zhí)行順序

主構(gòu)造函數(shù)不能包含任何的代碼。初始化的代碼可以放到以 init 關(guān)鍵字作為前綴的初始化塊(initializer blocks)中。

在實(shí)例初始化期間,初始化塊按照它們出現(xiàn)在類體中的順序執(zhí)行,與屬性初始化器交織在一起:
下邊4句的結(jié)果是按順序打印的

class InitOrderDemo(name: String) {
    val firstProperty = "First property: $name".also(::println)
    
    init {
        println("First initializer block that prints ${name}")
    }
    
    val secondProperty = "Second property: ${name.length}".also(::println)
    
    init {
        println("Second initializer block that prints ${name.length}")
    }
}

如果類有一個(gè)主構(gòu)造函數(shù),每個(gè)次構(gòu)造函數(shù)需要委托給主構(gòu)造函數(shù), 可以直接委托或者通過別的次構(gòu)造函數(shù)間接委托。委托到同一個(gè)類的另一個(gè)構(gòu)造函數(shù)用 this 關(guān)鍵字即可:

class Person(val name: String) {
    constructor(name: String, parent: Person) : this(name) {
        parent.children.add(this)
    }
}

初始化塊中的代碼實(shí)際上會(huì)成為主構(gòu)造函數(shù)的一部分。委托給主構(gòu)造函數(shù)會(huì)作為次構(gòu)造函數(shù)的第一條語句,因此所有初始化塊中的代碼都會(huì)在次構(gòu)造函數(shù)體之前執(zhí)行。即使該類沒有主構(gòu)造函數(shù),這種委托仍會(huì)隱式發(fā)生,并且仍會(huì)執(zhí)行初始化塊:
下邊init代碼先執(zhí)行的

class Constructors {
    init {
        println("Init block")
    }

    constructor(i: Int) {
        println("Constructor")
    }
}
lateinit 和by lazy

lateinit 是給var用的,而且必須給予值,頁面銷毀的時(shí)候如果沒有賦值,就掛了。
by lazy是給val用的, 后邊跟一個(gè)代碼塊,代碼塊最后一行就是返回值,并且代碼塊只會(huì)執(zhí)行一次,也就是第一次調(diào)用s這個(gè)變量的時(shí)候println會(huì)打印,再后邊調(diào)用s這個(gè)值,就不會(huì)執(zhí)行這個(gè)代碼塊了,s已經(jīng)有值了,直接返回即可。

        val s:String by lazy {
            println("lazy==============")
            "xxxx"
        }

        lateinit var ss:String
覆蓋屬性

在超類中聲明然后在派生類中重新聲明的屬性必須以 override 開頭,并且它們必須具有兼容的類型。每個(gè)聲明的屬性可以由具有初始化器的屬性或者具有 getter 方法的屬性覆蓋

open class Foo {
    open val x: Int get() { …… }
}

class Bar1 : Foo() {
    override val x: Int = ……
}

你也可以用一個(gè) var 屬性覆蓋一個(gè) val 屬性,但反之則不行.因?yàn)橐粋€(gè) val 屬性本質(zhì)上聲明了一個(gè) getter 方法,而將其覆蓋為 var 只是在子類中額外聲明一個(gè) setter 方法。你可以在主構(gòu)造函數(shù)中使用 override 關(guān)鍵字作為屬性聲明的一部分。

interface Foo {
    val count: Int
}

class Bar1(override val count: Int) : Foo

class Bar2 : Foo {
    override var count: Int = 0
}
覆蓋方法

2個(gè)父類有同名的方法,子類咋調(diào)用,用尖括號(hào)聲明父類

open class A {
    open fun f() { print("A") }
    fun a() { print("a") }
}

interface B {
    fun f() { print("B") } // 接口成員默認(rèn)就是“open”的
    fun b() { print("b") }
}

class C() : A(), B {
    // 編譯器要求覆蓋 f():
    override fun f() {
        super<A>.f() // 調(diào)用 A.f()
        super<B>.f() // 調(diào)用 B.f()
  }
}

擴(kuò)展函數(shù)

定義也比較簡(jiǎn)單,想擴(kuò)展哪個(gè)類,就點(diǎn)一下

class D:()
fun D.foo() = "d"

擴(kuò)展屬性

擴(kuò)展屬性不能有初始化器,他們的行為只能由顯式提供的 getters/setters 定義。

val <T> List<T>.lastIndex: Int
    get() = size - 1

消費(fèi)者 in, 生產(chǎn)者 out

如下方法里的參數(shù),有個(gè)in修飾,如果用out修飾,你在方法體里邊無法修改args參數(shù)的,in可以修改

override fun invoke(proxy: Any?, method: Method, args: Array<in Any>): Any? {}

可變參數(shù)

java里省略號(hào)表示可變參數(shù),可以傳多個(gè)參數(shù),也可以傳個(gè)數(shù)組,可kotlin調(diào)用的時(shí)候咋辦?

//java里代碼如下
public native Object invoke(Object obj, Object... args)

//kotlin里我們拿到的是個(gè)數(shù)組,下邊的參數(shù)args
override fun invoke(proxy: Any?, method: Method, args: Array<in Any>)
//使用的時(shí)候如下,前邊加個(gè)星號(hào)
method.invoke(xxx,*args);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line),也就是一...
    悟名先生閱讀 4,546評(píng)論 0 13
  • 寫在開頭:本人打算開始寫一個(gè)Kotlin系列的教程,一是使自己記憶和理解的更加深刻,二是可以分享給同樣想學(xué)習(xí)Kot...
    胡奚冰閱讀 1,408評(píng)論 0 6
  • Google在今年的IO大會(huì)上宣布,將Android開發(fā)的官方語言更換為Kotlin,作為跟著Google玩兒An...
    藍(lán)灰_q閱讀 77,191評(píng)論 31 489
  • 前言 人生苦多,快來 Kotlin ,快速學(xué)習(xí)Kotlin! 什么是Kotlin? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,688評(píng)論 9 118
  • 昨天本打算寫點(diǎn)什么,可是惰性又打敗了我。 昨天可謂喜憂參半,爸爸檢查身體一切都好,為喜;兒子班主任發(fā)...
    淺唱低吟品生活閱讀 202評(píng)論 0 0

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