什么是对象表达式
Java当中匿名内部类在很多场景下得到了大量的使用,而Kotlin的对象表达式就是为了解决匿名内部类的一些缺陷而产生的
我们来回顾一下匿名内部类:
- 既然叫匿名内部类,这个类是没有名字的。
- 匿名内部类本身一定是继承了某一个父类,或者是实现了某一个接口
- Java运行时会将该匿名内部类当做它所实现的接口或者是所继承的父类来看待
匿名内部类所提供的功能,对象表达式都可以支持,匿名内部类有的限制,对象表达式可以突破这个限制。
对象表达式的格式:
object[:若干个父类型,中间用逗号隔开]{
}
interface MyInterface{
fun myPrint(i:Int)
}
abstract class MyAbstractClass{
abstract val age:Int
abstract fun printMyAbstractClassInfo()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main10)
val myObject = object : MyInterface {
override fun myPrint(i: Int) {
println("i的值是$i")
}
}
myObject.myPrint(100)
}
这段代码就是一个典型的对象表达式的应用。其实可以理解成一个匿名内部类的意思,都表示实现了一个接口,把接口里面的方法都实现出来,然后返回来一个对象。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main10)
var myObject2 = object {
init {
println("初始化块zhix")
}
var myProperty = "hello world"
fun myMethod() = "myMethod()"
}
myObject2.myMethod()
}
这种是不实现任何接口和不继承任何抽象类的对象表达式
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main10)
var myObject3 = object : MyInterface, MyAbstractClass() {
override fun myPrint(i: Int) {
println("i的值是$i")
}
override val age: Int
get() = 30
override fun printMyAbstractClassInfo() {
println("printMyAbstractClassInfo 执行")
}
}
myObject3.myPrint(200)
myObject3.age
myObject3.printMyAbstractClassInfo()
}
这种是对象表达式的多个父类的情况。
class MyClass {
private var myObject = object {
fun output(){
println("output invoked")
}
}
fun myTest(){
myObject.output()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main10)
var myClass = MyClass()
myClass.myTest()
}
这样是没问题的,但是我把myObject的private去掉,会报错。
这个涉及到对象表达式的一些注意事项:
匿名对象只能在局部变量范围内或者是private修饰的成员变量范围内才能被识别出其真正的类型。
如果将匿名对象当做一个public方法的返回类型或者是public属性的类型(就是上面去掉private的情况),那么该方法或者属性的真正类型就是该匿名对象所声明的父类型,如果没有声明任何父类型,其类型就是Any,在这种情况下,匿名对象所声明的任何成员都是无法访问。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main10)
var myObject2 = object {
init {
println("初始化块zhix")
}
var myProperty = "hello world"
fun myMethod() = "myMethod()"
}
myObject2.myMethod()
}
这个例子就是在局部变量范围内,是在main方法里面声明的,这样真正的类型才能被编译器识别。
method2()是internal声明的方法,方法的类型是internal的,不是private的,显然表达式的返回的结果的真正类型是Any类型,Any类型里面是没有str属性的。
Java的匿名内部类和Kotlin的对象表达式的区别:
Java中匿名内部类想要访问外部类的属性或者变量,需要将变量加final。然而Kotlin的对象表达式是没有这个限制的,kotlin对象表达式是可以访问外层的变量,与Java不同的是,外层变量无需声明为final。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main11)
var i = 10
var myObject = object {
fun myMethod() {
i++
}
}
myObject.myMethod()
}
局部变量范围内定义对象表达式,是可以访问外部的变量。
对象表达式是可以替换Java的匿名内部类的,举个实际例子。