使用kotlin已經有一段時間了,可是看一些開源項目總以爲本身只是學了點皮毛。正好組內還沒人熟悉kotlin進階相關知識,所以也是決定以此文來作個分享,開闊下技術視野java
Kotlin 中 雙冒號操做符 表示把一個方法當作一個參數,傳遞到另外一個方法中進行使用,通俗的來說就是引用一個方法。express
println(::methon2)
fun methon2() {
println("methon2")
}
結果:
fun methon2(): kotlin.Unit
複製代碼
函數的參數(一般是最後一個)能夠用 vararg 修飾符標記:編程
fun main(args: Array<String>) {
hello(1,2,string = "hello")
hello(1,2,3,string = "world")
val asList = asList("2", "3")
println(asList.toString())
}
//這裏並不知道有幾個int的 vararg表示變長參數
fun hello(vararg intParameter:Int,string: String){
for (i in intParameter) {
println(i)
}
println(string)
}
fun <T> asList(vararg ts: T): List<T> {
val result = ArrayList<T>()
for (t in ts) // ts is an Array
result.add(t)
return result
}
結果:
1
2
hello
1
2
3
world
[2, 3]
複製代碼
也可稱爲閉包,本質是匿名函數,這裏從最基礎的點擊事件講起bash
{ 參數1: 類型, 參數2: 類型 -> 表達式 }
複製代碼
功能:點擊隱藏該控件
// java代碼:
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
v.setVisibility(View.GONE);
}
});
// kotlin 代碼:
// 一、kotlin 最原始寫法
tv.setOnClickListener(object : View.OnClickListener{
override fun onClick(v: View) {
v.visibility=View.GONE
}
})
// 二、匿名函數改爲lambda寫法
tv.setOnClickListener({ v:View -> v.visibility=View.GONE })
// 三、當lambda是函數的惟一實參,就能夠去掉空的小括號對
tv.setOnClickListener { v:View -> v.visibility=View.GONE }
//四、若是lambda的參數的類型能夠被編譯器推導出來,就能夠省略它
tv.setOnClickListener { v -> v.visibility=View.GONE }
// 五、若是lambda只有一個參數,那麼這個參數也能夠省略掉。代碼中引用這個參數的地方能夠經過編譯器自動生成的名稱it來替代
tv.setOnClickListener { it.visibility=View.GONE}
複製代碼
定義一個比較測試閉包
val test = if (5 > 3) {
println("yes")
} else {
println("no")
}
methon1 { methon2() }
fun methon1(body: () -> Unit) {
body()
}
運行結果:
fun methon2(): kotlin.Unit
methon2
fun main(args: Array<String>) {
val method = makeFun()
method()
method()
method()
}
// 函數返回值是一個lambda表達式
fun makeFun(): ()->Unit{
var count = 0
return fun(){
println(++count)
}
}
// 運行結果
1
2
3
複製代碼
聲明一個擴展函數,咱們須要用一個 接收者類型 也就是被擴展的類型來做爲他的前綴閉包
print("100".appendStr("%"))
/**
* this 就是.前面的String,即這裏是100
* @receiver String
* @param string String
* @return String
*/
fun String.appendStr(string: String):String{
return this+string
}
運行結果:
100%
複製代碼
在Android中一般能夠寫在BaseActivity/BaseFragment中,至關於給Activity、Fragment增長新功能app
open class BaseActivity : Activity() {
fun Context.toast(msg: String) {
if (TextUtils.isEmpty(msg)) {
return
}
Toast.makeText(this, msg, Toast.LENGTH_SHORT)
}
}
實現類調用
toast("這波操做666")
複製代碼
lazy() 方法接收一個lamda做爲參數並返回一個 Lazy實例, 能夠實現延遲加載: 第一次調用 get()時執行傳入 lazy()的lambda表達式並保存結果, 後續對get()的調用只返回保存的結果.編程語言
Delegates.observable()有兩個參數: 初始值和變化觀察器. 每次代理屬性被賦予值的時候都會調用觀察器(在賦值操做以後).觀察器有三個參數:屬性類型, 舊值和新值.ide
定義方法:
val/var <property name>:<Type> by <expression>
代理者須要實現相應的getValue/setValue方法
class AttrDelegate{
// val,不可變的,第一次訪問name才賦值
val name by lazy {
println("這句話只會打印一次")
"888"
}
val age by MyDelegate()
var age2 by MyDelegate()
}
fun main(args: Array<String>) {
var attrDelegate=AttrDelegate()
println(attrDelegate.name)
println(attrDelegate.name)
println(attrDelegate.age)
println(attrDelegate.age2)
attrDelegate.age2="male"
println(attrDelegate.age2)
}
// 爲何不是繼承lazy
class MyDelegate{ //重載操做符的函數須要用 operator 修飾符標記。
private var value: String? = null
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
println("getValue: $thisRef -> ${property.name}")
return value?: ""
}
/**
* 要代理var的屬性,除了實現getValue以外還須要再實現setValue
*/
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String){
println("setValue, $thisRef -> ${property.name} = $value")
this.value = value
}
}
運行結果:
這句話只會打印一次
888
888
getValue: com.sunkeding.kotlin.delegate.AttrDelegate@238e0d81 -> age
getValue: com.sunkeding.kotlin.delegate.AttrDelegate@238e0d81 -> age2
setValue, com.sunkeding.kotlin.delegate.AttrDelegate@238e0d81 -> age2 = male
getValue: com.sunkeding.kotlin.delegate.AttrDelegate@238e0d81 -> age2
male
複製代碼
密封類用來表示受限的類繼承結構:當一個值爲有限幾種的類型, 而不能有任何其餘類型時。在某種意義上,他們是枚舉類的擴展:枚舉類型的值集合 也是受限的,但每一個枚舉常量只存在一個實例,而密封類 的一個子類能夠有可包含狀態的多個實例。函數
聲明一個密封類,使用 sealed 修飾類,密封類能夠有子類,可是全部的子類都必需要內嵌在密封類中。測試
sealed 不能修飾 interface ,abstract class(會報 warning,可是不會出現編譯錯誤)
sealed class Student{
abstract fun speak()
class Boy:Student() {
override fun speak() {
}
}
class Girl:Student() {
override fun speak() {
}
}
}
複製代碼
概念:高階函數是將函數用做參數或返回值的函數。
infix函數必須知足如下要求
println(1.add(2))
println(1 add 2)
infix fun Int.add(x: Int): Int {
return this + x
}
運行結果:
3
3
複製代碼
概念:f(g(x))
/**定義兩個函數*/
val add5 = {i: Int -> i + 5} //加5
val multiplyBy2 = {i: Int -> i * 2} //乘2
fun main(args: Array<String>) {
// println(multiplyBy2(add5(8))) //(5 + 8) * 2
//
// val add5AndMultiplyBy2 = add5 andThen multiplyBy2
// val add5ComposeMutiplyBy2 = add5 compose multiplyBy2
// println(add5AndMultiplyBy2(8)) //m(x)= f(g(x)) (8+5)*2
// println(add5ComposeMutiplyBy2(8)) //m(x) = g(f(x)) 8*2+5
val add5AndMultiplyBy2 = add5.andThen(multiplyBy2)
val add5ComposeMutiplyBy2 = add5.compose(multiplyBy2)
println(add5AndMultiplyBy2(8))
println(add5ComposeMutiplyBy2(8))
}
/**定義一個複合函數*/
/**
* p一、p2是參數
* R是返回值
* andThen擴展函數
* 參數:Function1<P2,P2>,第一參數是參數類型,第二個參數是返回值類型
* 返回值:Function1<P1,R>
* infix中綴表達式
*/
infix fun <P1,P2,R> Function1<P1,P2>.andThen(function: Function1<P2,R>): Function1<P1,R>{
//進行復合
//返回了一個函數
return fun (p1: P1):R{
//函數裏面function.invoke把這個function又調用了一遍
//而後又把本身的返回值傳給了上去
return function.invoke(this.invoke(p1))
}
}
infix fun <P1,P2,R> Function1<P2,R>.compose(function: Function1<P1,P2>):Function1<P1,R>{
return fun (p1: P1):R{
return this.invoke(function.invoke(p1))
}
}
運行結果:
26
21
複製代碼
class Person( var name: String, var age: Int){
private fun eat(){
println("eat")
}
fun speak(string: String){
println(string)
}
override fun toString(): String {
return "Person(name='$name', age=$age)"
}
}
val clazz = Class.forName("com.study.reflections.Person")
val newInstance = clazz.getConstructor(String::class.java,Int::class.java).newInstance("zhangsan",10)
println(newInstance)
val method = newInstance.javaClass.getDeclaredMethod("eat").apply { isAccessible=true }
val method2 = newInstance.javaClass.getDeclaredMethod("speak", String::class.java)
method.invoke(newInstance)
method2.invoke(newInstance,"說個666吧")
val newInstance = clazz.getConstructor(String::class.java,Int::class.java).newInstance("zhangsan",10)
println(newInstance)
val method = newInstance.javaClass.getDeclaredMethod("eat").apply { isAccessible=true }
val method2 = newInstance.javaClass.getDeclaredMethod("speak", String::class.java)
method.invoke(newInstance)
method2.invoke(newInstance,"說個666吧")
運行結果:
Person(name='zhangsan', age=10)
eat
說個666吧
複製代碼