使用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吧
复制代码