引言
在Kotlin中,我可以声明普通类、数据类、静态类,它也有抽象类和接口,其中abstract关键字只能作用在普通类。
类和对象
普通类
Kotlin中的普通类通过class关键字定义,这种类默认都是final类型的,无法被继承。如果希望被继承,需要在前面增加open关键字
class Person(var id:Int?) { // id可为null
var name:String? = null
constructor():this(999) // 重载
cosntructor(id:Int, name:String):this(id) { // 重载
this.name = name
}
}
fun main() {
var ps1= Person()
var ps2 = Person(20)
}
抽象类
通过abstract class定义一个抽象类,默认是open class
abstract class BaseActivity {}\
接口
接口的定义和java非常类似
interface UserApi {}
静态类
object StudentManager{
fun show() { // 注意,这是单例方法
// ..
}
@JvmStatic // 增加这个关键字才是static方法
fun show2(){
// ..
}
}
内部类
静态内部类
class A {
object Instance {
var instance = A()
}
compannion object { // A的静态方法
fun getInstance() : A = Instance.instance
}
}
// A.getInstance()
普通内部类
class A {
inner class Class2 {
}
class Class3 {
// 注意这个不是内部类
}
}
扩展
class User(val name:String)
fun User.print() {
print("用户名: $name")
}
fun main() {
var user = User()
user.print()
}
Kotlin扩展可以在不修改原类的基础上增加功能,原类不受影响。没有真正增加代码,扩展的内容不参与多态,调用的哪个就是哪个。但如果子类的扩展覆盖了父类的扩展,如果用子类去调用该函数,会使用子类的扩展函数。总之,谁调用就使用谁的扩展。
属性也可以扩展,属性初始化只能通过getter/setter实现
当然也可以对伴生对象进行扩展,以实现静态化
委托
类委托
类委托和代理模式很类似,从java的角度看,就是类A实现一个公共接口或直接继承B,然后内部持有一个B类对象。进而可在A类中使用B类的方法。
Kotlin很容易实现上述方式
interface Base {
fun print()
}
class BaseImpl(val x:Int): Base{
override fun print() {
println(x)
}
}
class Driver(b:Base) : Base by b
fun main() {
var driver = BaseImpl(10)
Driver(driver).print()
}
从上述代码可以看出,这里的Driver的print委托给BaseImpl实现
属性委托
val/var [属性名]:[类型] by [表达式]
其中表达式指的是委托代理类,该属性的get和set会交给该类的getValue和setValue实现。
class Example{
var p : String by Delegate()
}
// 委托的类
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty): String {
return "$thisRef, 这里委托了 ${property.name} 属性"
}
operator fun setValue(thisRef: Any?, property: KProperty, value: String) {
println("$thisRef 的 ${property.name} 属性赋值为 $value")
}
}
fun main(args: Array) {
val e = Example()
println(e.p) // 访问该属性,调用 getValue() 函数
e.p = "Runoob" // 调用 setValue() 函数
println(e.p)
}
输出结果为:
Example@433c675d, 这里委托了 p 属性
Example@433c675d 的 p 属性赋值为 Runoob
Example@433c675d, 这里委托了 p 属性
属性懒加载:
var lazyValue:String by lazy{
// loading property
}
该属性第一次用到时会调用lazy{}代码块中的内容,并缓存到内存中,第二次就直接从内存中获取到值了。
属性记录器
class User{
var name:String by Delegates.observable("初始值"){
prop, old, new ->
Log.d("old:$old, new:$new")
}
}
fun main(){
val user = User()
user.name = "1"
user.name = "2"
}
当上述main开始执行时,输出:
old:初始值,new:1
old:1,new:2
属性Map映射器
class Site(val map:Map){
val name:String by map
val url:String by map
}
fun main(){
var site = Site(mapOf(
"name" to "百度"
"url" to "http://www.baidu.com"
))
print(site.name) // 百度
print(site.url) // http://www.baidu.com
}
也就是说,我们只需构造一个和map结构差不多的类,kotlin就会自动帮忙解析,并将属性设置该该对象。
如果属性为var,则需要把Map换成MutabbleMap
class Site(val map:MutabbleMap){
val name:String by map
val url:String by map
}
fun main(){
var site = Site(mutableMapOf(
"name" to "百度"
"url" to "http://www.baidu.com"
))
print(site.name) // 百度
print(site.url) // http://www.baidu.com
}
函数类型委托
fun example(computeFoo: () -> Foo) {
val memoizedFoo by lazy(computeFoo)
if (someCondition && memoizedFoo.isValid()) {
memoizedFoo.doSomething()
}
}
其中 ()->Foo 是一个函数类型,也就是一个返回Foo的函数,类似于
interface A{ void Foo();},相当于传了new A。
然后memoizedFoo委托给computeFoo执行。
Kotlin和Java互调
Kotlin可以支持不写类直接写函数,而Java调用Kotlin这样的函数式,需要写文件名Kt.函数名即可。
Java和Kotlin互调时,Kotlin调用java代码,拥有更多写法,支持闭包,lombda等。
总结
本小节主要介绍了面向对象的基本知识和类委托、属性委托等