目录
一、属性代理
什么是代理,请童鞋们自行百度~。那什么是属性代理呢?我们先看下面的例子:
//代理类
class DelegateTest{
var v by Delegates.notNull<Any>()
operator fun getValue(thisRef:Any?,property:KProperty<*>):Any{
println("我是DelegateTest中的getValue")
return v
}
operator fun setValue(thisRef: Any?,property: KProperty<*>,value:Any){
println("我是DelegateTest中的setValue")
v = value
}
}
//测试类
class TestA{
var value by DelegateTest()
}
fun main(args: Array<String>) {
val ta = TestA()
ta.value = "vvvvv"
println("------------------")
println("我是get方法:${ta.value}")
}
输出如下
我是DelegateTest中的setValue
------------------
我是DelegateTest中的getValue
我是get方法:vvvvv
DelegateTest类是一个实现了代理功能的类,这个类中实现了setValue和getValue的两个方法,这个方法是必要实现的。
TestA是测试类,其中的value通过by关键字实现了被代理的功能
我们在main方法中设置了TestA类中的value值,此时执行到了DelegateTest中的setValue方法,相当于DelegateTest对set这个动作进行了拦截,然后做了定制的操作;随后又打印了TestA中的value值,相当于是get动作,DelegateTest中的getValue方法被执行。
代理类的setValue和getValue中可以实现业务的操作,比如属性值得存储和获取等,简化和方法了我们的操作。
Kotlin中也有很多实现了属性代理的类,供程序使用,比如上面DelegateTest中的Delegate这个类,这个类有三个api:Delegate.notNull,Delegate.observable,Delegate.vetoable
Delegate.notNull
这个方法很好理解,使用了Delegate.notNull的属性不能为空,但是可以先被申明出来。在Kotlin中是不能不对属性进行初始化的,而使用了Delegate.notNull属性之后,表示此属性的初始化操作可以延后来做,具体什么时候做由使用者来决定。
Delegate.observale
我们先看这个方法的使用
class Student{
var name:String by Delegates.observable(initialValue = "Beijing",onChange = {property, oldValue, newValue ->
println("property: ${property.name} oldValue: $oldValue newValue: $newValue")
})
}
fun main(args: Array<String>){
val student = Student()
student.name = "Beijing"
student.name = "Chengde"
}
输出
property: name oldValue: Beijing newValue: Beijing
property: name oldValue: Beijing newValue: Chengde
作用显而易见,使用了此方法的属性,当属性值发生改变时,就会执行observable方法中第二个参数实现的方法
Delegate.vetoable
我们先看一下使用的代码
class VetoableTest{
var name:String by Delegates.vetoable(initialValue = ""){property, oldValue, newValue ->
if(newValue=="gzc"){
return@vetoable true
}else{
return@vetoable false
}
}
}
fun main(args: Array<String>) {
val vetoableTest = VetoableTest()
vetoableTest.name = "liming"
println("name:${vetoableTest.name}")
vetoableTest.name = "gzc"
println("name:${vetoableTest.name}")
}
输出:
name:
name:gzc
使用了这个方法的属性,在赋值的时候先会进行比较,符合条件的话,返回true,赋值成功;不符合条件的话,返回false,赋值为默认值
二、数据类
数据类也是Kotlin中特有的类型,类被data关键字修饰的话,可以实现toString,equals/hashCode,componentN,copy方法,就不需要我们手动的去写了
如下:
//普通类
class CommonClass(val name:String,val age:Int)
//数据类
data class DataClass(val name:String,val age:Int)
fun main(args: Array<String>) {
val commonClass = CommonClass("gzc",27)
println(commonClass)
val dataClass = DataClass("liming",26)
println(dataClass)
}
输出
CommonClass@7cc355be
DataClass(name=liming, age=26)
使用数据类的时候一定要注意,当类成为数据类的时候,这个在字节码中已经被final修饰,并且没有无参构造器,所以使用的时候你可能会遇到各种奇葩的问题,针对上述的问题,我们使用两个插件来解决:allopen和noarg,我们只需要在gradle或者maven中添加这两个插件。具体的使用,推荐博客