提示:本文为作者阅读Kotlin中文站学习笔记,建议读者移步Kotlin中文站完整学习。
有时候我们需要对某个类做轻微改动的类的对象,而不用为之显式声明新的子类。Java中用匿名内部类来处理这种情况,Kotlin中则用对象表达式和对象声明来实现。
对象表达式
要创建一个继承自某个类的匿名类的对象,我们可以这么写:
fun addListener(){
var edt:EditText= EditText(this)
edt.addTextChangedListener(object :TextWatcher{//创建一个实现TextWatcher接口的匿名类对象
override fun afterTextChanged(s: Editable?) {
TODO("not implemented")
count++
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
TODO("not implemented")
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
TODO("not implemented")
}
})
}
我们也可以创建一个不继承任何超类的匿名类的对象:
fun foo(){
val adHoc=object {//创建一个不继承任何超类的匿名类对象
var x:Int=0
var y:Int=0
fun printXY(){
print("x="+x+"y="+y)
}
}
adHoc.printXY()
}
注意,匿名对象可以用作只在本地和私有作用域中声明的类型。如果你使用匿名对象作为公有函数的返回类型或者用作公有属性的类型,那么该函数或属性的实际类型会是匿名对象声明的超类型,如果你没有声明任何超类型,就会是 Any。在匿名对象中添加的成员将无法访问。
class O{
//私有函数,返回类型是匿名对象
private fun foo()=object {
val str:String="Hello Kotlin!"
}
//公有函数,返回类型是Any
fun publicFoo()=object {
val str:String="Hello Kotlin!"
}
fun bar(){
foo().str //可以访问增加的成员
publicFoo().str //无法访问增加的成员
}
}
跟java匿名内部类一样,对象表达式中可以访问包含它的作用域的变量(与Java不同的是这不仅限于final变量):
fun addListener(){
var count:Int=0
var edt:EditText= EditText(this)
edt.addTextChangedListener(object :TextWatcher{
override fun afterTextChanged(s: Editable?) {
TODO("not implemented")
count++//对象表达式中可以访问包含它的作用域中的变量
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
TODO("not implemented")
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
TODO("not implemented")
}
})
}
对象声明
Kotlin,我们可以这样使用一个单例模式:
object OkClient{
private val client = OkHttpClient()
fun instance() = client
}
这成为对象声明。它总是在object关键字后面跟一个名称。跟变量声明一样,对象声明不是一个表达式,所以不能跟在赋值语句的右边。
要引用该对象我们直接使用其名称即可:
fun getHtml(url: String): String {
val client = OkClient.instance()
val request = Request.Builder()
.url(url)
.build()
val response = client.newCall(request).execute()
return response.body().string()
}
伴生对象
类内部的对象声明可以用companion关键字标记:
class R{
companion object {
private var mInstance:R=R()
fun getInstance():R{
return mInstance
}
}
}
对伴生对象的成员可以只通过类名作为限定符来访问:
R.getInstance()
注意:即使伴生对象的成员看起来像Java中类的静态成员,但在运行时它仍然是真实对象的实例成员,例如,它还可以实现接口:
interface Factory<T>{
fun cerate():T
}
class R{
companion object :Factory {
private var mInstance:R=R()
override fun cerate(): R {
mInstance=R()
return mInstance
}
}
}
对象表达式与对象声明之间的差别: