Kotlin object 总结
Posted Eli Shaw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin object 总结相关的知识,希望对你有一定的参考价值。
object 关键字在 kotlin 中有两个用法,一个连用。一种用作对象表达式,另一种用作对象声明,它还可以与 companion 关键字一起使用,被称为伴生对象。
一、总结
㈠ object 用于对象表达式:
相当于 Java 中的匿名内部类,与匿名内部类不同点如下:
1.object 的对象表达式可以实现多个接口或实体类。
2.object 实现的匿名内部类,在此匿名内部类中使用外部方法中的形参或外部方法中的局部变量,无须使用 final 修饰,可直接操作。
㈡ object 用于对象声明
相当于自动实现了 Java 中的单例模式。
㈢ object 与 companion 关键字连用
实现一个伴生对象,在伴生对象中定义的属性跟方法,在 Kotlin 的代码中使用,相当于 Java 中的静态方法与静态变量。只是在 Java 中伴生对象又像是一个静态内部类,如果不使用 const 修饰的属性。需要使用伴生对象名引用属性或方法。
二、对象表达式
对象表达式,类似于 Java 中的匿名内部类,如下代码
val handler: Handler = object : Handler()
override fun handleMessage(msg: Message?)
super.handleMessage(msg)
when (msg?.what)
0 -> mTvText?.text = "我是Handler"
上边使用 object 实现了一个 Handler 的匿名内部类,并实现了 handlerMessage 方法,我们将此代码转换为 Java,即可看到
private final Handler handler = (Handler)(new Handler()
public void handleMessage(@Nullable Message msg)
super.handleMessage(msg);
Integer var2 = msg != null ? msg.what : null;
if (var2 != null)
if (var2 == 0)
TextView var10000 = MainActivity.access$getMTvText$p(MainActivity.this);
if (var10000 != null)
var10000.setText((CharSequence)"我是Handler");
);
从上面代码可以看到,对象表达式,与 Java 中的匿名内部类,相当于是一样的(注:相当于一样,并不代表是一样的,Kotlin 有自己的编译器,并不能与 Java 代码完全对等)。
但是它与 Java 的匿名内部类是有区别的,区别在以下几点:
1.object 的对象表达式可以实现多个接口或实体类。
2.object 实现的匿名内部类,在此匿名内部类中使用外部方法中的形参或外部方法中的局部变量,无须使用 final 修饰,可直接操作。
三、对象声明
Kotlin 使用 object 关键字来声明一个对象,使用 object 声明的对象类似于 Java 中的单例类。
object SingleTest
val name: String = "我是测试单例类属性 name"
fun singleTest()
println("我是测试单例类方法 singleTest")
上面的代码即定义了一个名为 SingleTest 的单例类,此代码转换成 Java 后如下:
public final class SingleTest
@NotNull
private static final String name = "我是测试单例类属性 name";
public static final SingleTest INSTANCE;
@NotNull
public final String getName()
return name;
public final void singleTest()
String var1 = "我是测试单例类方法 singleTest";
System.out.println(var1);
static
SingleTest var0 = new SingleTest();
INSTANCE = var0;
name = "我是测试单例类属性 name";
从上面的代码中可以看出,在 object 中的属性,都会被修饰为 static 类型。
虽然在编译成的 Java 代码中没有将构造方法私有。但是,在使用时确实不能实例 object 修饰的类。如下代码会报错:
//这样使用会报错,说明使用 object 修饰的对象类,构造方法默认为 private 了,因此使用实例化单例类会报错。
val singleTest:SingleTest = SingleTest()
object实现的单例类在使用上与 Java 也有一些分别,在 Kotlin 中可以直接使用 object单例类名.方法|属性。使用代码如下:
KOTLIN
SingleTest.singleTest() //对象名.方法名
SingleTest.name //对象名.属性名
JAVA
SingleTest.INSTANCE.getName();
SingleTest.INSTANCE.singleTest();
从上面的代码中可以看出,在 Java 的类中使用还是要引用 INSTANCE 属性,而 Kotlin 中无需引用。
这里还有一个注意点,当在一个类中使用 object 定义一个对象时,此对象的特性与伴生对象很相似,代码如下
class Objects
object Users
val name: String = "我是 object 中的属性 name"
const val age: String = "我是 object 中的属性 age"
fun method(): String
return "我是 object 中的方法 method"
上面代码转换成 Java 后如下:
public final class Objects
public static final class Users
@NotNull
private static final String name = "我是 object 中的属性 name";
@NotNull
public static final String age = "我是 object 中的属性 age";
public static final Objects.Users INSTANCE;
@NotNull
public final String getName()
return name;
@NotNull
public final String method()
return "我是 object 中的方法 method";
static
Objects.Users var0 = new Objects.Users();
INSTANCE = var0;
name = "我是 object 中的属性 name";
我们看代码,这与伴生对象很相似,与直接定义的 object 类不同的是,此类是静态的内部类。而直接定义的 object 对象是普通 final 类。
但是他与伴生对象不同的是,object 静态的内部类被定义成了单例模式的,并且使用 const 修饰的属性还是属于当前定义的单例对象,并没有归属于外部类。
与伴生对象相同的是,使用 const 修饰的属性,还是 public static 类型的,并且没有定义 getter,setter 方法。
四、伴生对象
类内部的对象声明可以用 companion 关键字标记,这样它就与外部类关联在一起,我们就可以直接通过外部类访问到对象的内部元素。
class Users
companion object Factory
val name: String = "我是 companion 中的属性 name"
const val age: String = "我是 companion 中的属性 age"
fun method(): String
return "我是 companion 中的方法 method"
上面代码转换成 Java 后如下:
public final class Users
@NotNull
private static final String name = "我是 companion 中的属性 name";
@NotNull
public static final String age = "我是 companion 中的属性 age";
public static final Users.Factory Factory = new Users.Factory((DefaultConstructorMarker)null);
public static final class Factory
@NotNull
public final String getName()
return Users.name;
@NotNull
public final String method()
return "我是 companion 中的方法 method";
private Factory()
// $FF: synthetic method
public Factory(DefaultConstructorMarker $constructor_marker)
this();
从上面的代码可以看出,Java 中的伴生对象相当于是一个静态内部类,并且伴生对象的构造方法是私有的,也就是说伴生对象是无法被实例的。
再看伴生对象中定义的属性,最终归属于外部类。然而使用 const 修饰的属性被定义为 public static 类型。没有使用 const 修饰的属性,被定义为 private static 类型,并在伴生对象中生成了此属性的 getter 方法。
因此使用 const 修饰的属性,在使用的时候可以直接 外部类名.伴生对象的属性名 使用。使用代码如下
KOTLIN
Users.name //在 Kotlin 中其实隐藏了伴生对象的类名
Users.age // age 使用 const 关键字修饰的,属性于 Users 的公共静态属性
Users.method() // 访问到伴生对象的内部元素
JAVA
Users.Factory.getName(); //在 Java 中使用伴生对象,需要引用伴生对象名
String age = Users.age; //在 Java 中使用 const 修饰的伴生对象属性,必须使用一个变量来接收
Users.Factory.method(); //在 Java 中使用伴生对象,需要引用伴生对象名
我们可以省略掉该对象的对象名,然后使用 Companion 替代需要声明的对象名:
class Users
companion object
val name: String = "我是 companion 中的属性 name"
const val age: String = "我是 companion 中的属性 age"
fun method(): String
return "我是 companion 中的方法 method"
KOTLIN
Users.name //在 Kotlin 中其实隐藏了伴生对象的类名
Users.age // age 使用 const 关键字修饰的,属性于 Users 的公共静态属性
Users.method() // 访问到伴生对象的内部元素
JAVA
Users.Companion.getName(); //在 Java 中使用伴生对象,需要引用伴生对象名
String age = Users.age; //在 Java 中使用 const 修饰的伴生对象属性,必须使用一个变量来接收
Users.Companion.method(); //在 Java 中使用伴生对象,需要引用伴生对象名
我们看省略了伴生对象名,在 Kotlin 中使用还是老样子,但是在 Java 中使用,还是需要引用伴生对象名,不同的是,此处伴生对象名是默认的 Companion。
注意:一个类里面只能声明一个内部关联对象,即关键字 companion 只能使用一次。
之前有看到说在 object 或 companion object 中定义的属性或方法为静态方法或变量,这是错误的。他们在使用上确实跟静态方法和静态变量一样,但是在 Kotlin 中如果要定义静态方法或静态变量,一定要使用 @JvmStatic 注解修饰的变量或属性才为静态方法或静态变量,并且此关键字只能用在 object 或 companion object 中。
五、const 关键字
const 只能修饰 val
const 只允许在 top-level 级别和 object 中声明,使用方式如下:
const val THOUSAND = 1000 //用在类的外面
class Const
object MyObject //用在 object 中
const val constNameObject: String = "constNameObject"
val nameObject: String = "nameObject"
companion object //用在伴生对象中
const val constNameCompanionObject: String = "constNameCompanionObject"
val nameCompanionObject: String = "nameCompanionObject"
上面代码转换成 Java 后如下:
public final class ConstKt
public static final int THOUSAND = 1000;
// Const.java
package cn.eli.androidkotlin;
import kotlin.Metadata;
import kotlin.jvm.internal.DefaultConstructorMarker;
import org.jetbrains.annotations.NotNull;
public final class Const
@NotNull
public static final String constNameCompanionObject = "constNameCompanionObject";
@NotNull
private static final String nameCompanionObject = "nameCompanionObject";
public static final Const.Companion Companion = new Const.Companion((DefaultConstructorMarker)null);
public static final class MyObject
@NotNull
public static final String constNameObject = "constNameObject";
@NotNull
private static final String nameObject = "nameObject";
public static final Const.MyObject INSTANCE;
@NotNull
public final String getNameObject()
return nameObject;
static
Const.MyObject var0 = new Const.MyObject();
INSTANCE = var0;
nameObject = "nameObject";
public static final class Companion
@NotNull
public final String getNameCompanionObject()
return Const.nameCompanionObject;
private Companion()
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker)
this();
使用方式如下:KOTLIN
THOUSAND //在 kotlin 中可以直接使用定义在 top-level 级别的 const 常量
Const.MyObject.constNameObject //在 kotlin 中,定义在 object 中的 const val 与 val 使用上没有分别
Const.MyObject.nameObject //在 kotlin 中,定义在 object 中的 const val 与 val 使用上没有分别
Const.constNameCompanionObject //在 kotlin 中,定义在 companion object 中的 const val 与 val 使用上没有分别
Const.nameCompanionObject //在 kotlin 中,定义在 companion object 中的 const val 与 val 使用上没有分别
JAVA
int thousand = ConstKt.THOUSAND; //在 Java 使用定义在 top-level 级别的 const 常量,需要使用 Kotlin 生成的类名
String constNameObject = Const.MyObject.constNameObject; //在 Java 中,定义在 object 中的 const val 与 val 使用上有区别
String nameObject = Const.MyObject.INSTANCE.getNameObject(); //在 Java 中,定义在 object 中的 const val 与 val 使用上有区别
String constNameCompanionObject = Const.constNameCompanionObject; //在 Java 中,定义在 companion object 中的 const val 与 val 使用上有区别
String nameCompanionObject = Const.Companion.getNameCompanionObject(); //在 Java 中,定义在 companion object 中的 const val 与 val 使用上有区别
从上面的代码总结如下
㈠ const 用在 top-level 级别
会在当前类的第一行生成一个:"当前类名+Kt" 的类,在此类中定义 public static final 常量。在 Kotlin 中可以直接使用常量的名字,而在 Java 中需要加上 Kotlin 生成的“当前类名+Kt”。
㈡ const 用在 object
无论是否使用 const 修饰的属性,他都属于当前定义的对象。在使用时需要引用对象的名字,即:外部类.对象.属性
㈢ const 用在 companion object(伴生对象)
const 修饰的属性,将被定义在外部类中,在 Java 中可直接使用 外部类名.const 属性即可。
㈣ const val 与 val 的区别
const val 修饰的属性为 public staitc final 类型,可直接引用。
val 修饰的属性定义在普通类中为 private final 类型,定义在对象、伴生对象中为 private static final 类型。无论定义在哪里,都会为 val 修饰的属性创建 getter 方法,在访问的时候,实际调用的是其 getter 方法。
以上是关于Kotlin object 总结的主要内容,如果未能解决你的问题,请参考以下文章