在Java中又匿名类的概念,也就是说,在创建类的时候,无需指定类的名字。匿名类一般用于方法参数。基本理念就是方法需要接收一个类或者接口的实例,而这个实例只是在该方法中使用,没有必要单独再定义一个类,或者创建一个对象变量。因此,就在传入方法参数值的同时创建了该类的实例。代码例子如下:
public class JClass {
public void fun(){
System.out.println("jclass");
}
}
public class JClassTest {
public static void process(JClass jClass) {
jClass.fun();
}
public static void main(String[] agrs) {
process(new JClass() {
@Override
public void fun() {
System.out.println("haha jclass");
}
});
}
}
最终输出 haha jclass
在Kotlin中也有类似的功能,但不是匿名类,而是对象。与上面代码相同功能,下面是Kotlin代码:
object JClassTest {
fun process(jClass: JClass) {
jClass.`fun`()
}
@JvmStatic
fun main(agrs: Array<String>) {
process(object : JClass() {
override fun `fun`() {
println("haha jclass")
}
})
}
}
可以看到,要想建立一个对象,就要使用object关键字,该对对象要继承的类需要与object之间用冒号(:)分隔。
对象和类一样,只能有一个父类,但可以实现多个接口,下面的代码中,对象不仅继承了JClass类,还实现了JInterface接口:
process(object : JClass(), JInterface {
override fun printlnData() {
println("haha jinterface")
}
override fun `fun`() {
println("haha jclass")
}
})
如果只想建立一个对象,不想继承任何类,也不想实现任何接口,可以按下面的方式建立:
var data = object {
var value: String = "H"
}
匿名对象只能用在本地(函数)或private声明中。如果将匿名对象用于public函数的返回值,或者public属性的类型,那么Kotlin编译器会将这些函数或属性的返回类型重新定义为匿名对象的夫类型,如果匿名对象没有继承任何类,也没有实现任何接口,那么父类型就是Any。因此,添加在匿名对象中的任何成员都将无法访问。
class ObjectClass {
// private函数,返回类型是匿名对象本身,可以访问x
private fun foo() = object {
var x = 1
}
// public函数,由于匿名对象没有任何父类型,因此函数的返回类型是Any
public fun publicFoo() = object {
var x = 2
}
fun bar() {
var x = foo().x //可以访问
// var x2 = publicFoo().x // 编译错误,publicFoo返回的是Any对象
}
}
在Java中,匿名对象访问封闭作用域内的变量,需要用final声明该变量,这也就意味着在匿名对象中无法修改封闭作用域内变量的值。在Java8中,如果只是使用封闭作用域内的变量,该比那辆无需使用final,但一旦修改变量的值,就必须使用final进行修饰,其实在Java8中,,封闭作用域的变量是一个隐式的final变量。
但是在Kotlin中,在匿名对象中就可以任意访问封闭作用域内的变量,包括修改它的值:
fun main(agrs: Array<String>) {
var n = 10
process(object : JClass(), JInterface {
override fun printlnData() {
println("$n")
println(n++)
}
})
}
在Kotlin中并没有静态类成员的概念,但并不等于不能实现类似于静态类成员的功能。陪伴对象就是Kotlin中用来解决这个问题的语法糖。
如果在Kotlin类中定义对象,那么就称这个对象为该类的陪伴对象。陪伴对象要使用companion关键字声明:
class CompanionClass {
companion object {
val TAG = "JIA"
fun create(): CompanionClass = CompanionClass()
}
}
陪伴对象中定义的成员是可以直接通过类名访问的。
var instance=CompanionClass.create()
注意,虽然陪伴对象的成员看起来很像其他语言中的类的静态成员,但在运行期间,这些成员任然是真实对象的实例的成员,它们与静态成员是不同的。不过使用@Jvmtatic进行注释,Kotlin编译器会将其编译成Byte Code真正的静态方法。这些内容以后会详细介绍。