由于 Kotlin 中没有静态成员的概念, 因此 Kotlin 推出了一个有趣的语法糖: 对象. 那么对象能取代静态类成员吗? 该怎么做呢? 下面会详细介绍到.
对象表达式
在 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 真正的静态方法. 这些内容以后会详细介绍.
来源: https://juejin.im/post/5b67ae606fb9a04fd260b6a5