02-对象表达式
9.1.1 对象表达式
在Java中,匿名类是一个很重要的概念。创建匿名类时无须指定类名,因为没有名称,所以匿名类不可以声明对象,但可以创建对象。匿名类主要在方法的参数类型中使用,当类中的方法或属性不需要被重复利用时,匿名类是一种合适的选择。
public class Test {
public static void main(String[] args) {
//创建匿名类
Speak speak = new Speak() {
@Override
public void say() {
System.out.println("hello word");
}
};
speak.say();
}
}
interface Speak {
void say();
}
当子类的类体比较简单时,也可以考虑使用匿名类,匿名类一定是内部类,而且可以访问外嵌类的成员变量和方法。
Kotlin也提供了类似的功能,但不是匿名类,而是对象。要创建一个对象,需要使用关键字object,该对象和继承的匿名类对象之间使用冒号分隔,冒号用来表示继承关系。对于上面的Java代码,转化为Kotlin代码如下。
fun main(args: Array<String>) {
val speak = object : Speak {
override fun say() {
println("hello word")
}
}
speak.say()
}
internal interface Speak {
fun say()
}
如果超类中有一个构造函数,则必须传递适当的参数给构造函数,当出现多个超类时,可以由跟在冒号后面的逗号分隔列表。代码如下。
fun main(args: Array<String>) {
val ab: A = object : A(1), B {
override val y = 15
}
}
interface B {
//…
}
open class A(x: Int) {
open val y: Int = x
}
如果只需要建立一个对象,而不想从任何类继承,也不想实现任何接口,那么可以按照下面的方式建立对象。
fun foo() {
//建立一个对象,该对象没有任何父类型
val adHoc = object {
var x: Int = 0
var y: Int = 0
}
print(adHoc.x + adHoc.y)
}
匿名对象可以作用于本地和私有域中声明的类型,如果使用匿名对象作为公有函数的返回类型或者公有属性的类型,那么该函数或属性的实际类型是匿名对象声明的超类型;如果没有声明任何超类型,则默认为Any类型。代码如下。
class C {
// 私有函数,返回类型是匿名对象类型
private fun foo() = object {
val x: String = "x"
}
// 公有函数,返回类型是Any
fun publicFoo() = object {
val x: String = "x"
}
fun bar() {
val x1 = foo().x // 编译正确
val x2 = publicFoo().x // 编译错误,不能解析引用“x”
}
}
与Java的匿名内部类一样,Kotlin的对象表达式代码可以访问包含它的作用域变量,而不仅限于final类型的变量。