object关键词
Kotlin语法中,提供了我们一个非常简单就能创建单例的关键字,“object”,即可创建。如代码
object LogUtils {
fun test(){
Log.i("hello","i am test method")
}
fun print(){
Log.i("hello","i am LogUtils")
}
}
那么隐藏在object背后的魔力是什么呢?我们来反编译一下:
// class version 52.0 (52)
// access flags 0x31
public final class com/example/spider/LogUtils {
// compiled from: LogUtils.kt
// access flags 0x19
public final static Lcom/example/spider/LogUtils; INSTANCE(单例关键)
@Lorg/jetbrains/annotations/NotNull;() // invisible
// access flags 0x2
private <init>()V (私有化构造函数)
L0
LINENUMBER 6 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
RETURN
L1
LOCALVARIABLE this Lcom/example/spider/LogUtils; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x11
public final test()V
L0
LINENUMBER 9 L0
LDC "hello"
LDC "i am test method"
INVOKESTATIC com/example/spider/LogTest.test ()V
INVOKESTATIC com/example/spider/LogTest.test ()V
POP
L1
LINENUMBER 10 L1
RETURN
L2
LOCALVARIABLE this Lcom/example/spider/LogUtils; L0 L2 0
MAXSTACK = 2
MAXLOCALS = 1
// access flags 0x11
public final print()V
L0
LINENUMBER 13 L0
LDC "hello"
LDC "i am LogUtils"
INVOKESTATIC android/util/Log.i (Ljava/lang/String;Ljava/lang/String;)I
POP
L1
LINENUMBER 14 L1
RETURN
L2
LOCALVARIABLE this Lcom/example/spider/LogUtils; L0 L2 0
MAXSTACK = 2
MAXLOCALS = 1
// access flags 0x8
static <clinit>()V
NEW com/example/spider/LogUtils
DUP
INVOKESPECIAL com/example/spider/LogUtils.<init> ()V
PUTSTATIC com/example/spider/LogUtils.INSTANCE : Lcom/example/spider/LogUtils;
RETURN
MAXSTACK = 2
MAXLOCALS = 0
}
可以看到,实现单例的背后其实是声明了一个final static 修饰,名称是INSTANCE变量,并且添加了NotNull注解,通过final static保证了创建的单一。
内部原理
因为object的方便,很多初入kotlin的同学也许会通过这样调用一个方法,比如LogUtils.print(),这样是不是非常类似我们java的静态方法调用呢?久而久之,很多小同学就以为这是一个静态方法,这可是非常大的误解呀!我们反编译看下字节码
GETSTATIC com/example/spider/LogUtils.INSTANCE : Lcom/example/spider/LogUtils;
INVOKEVIRTUAL com/example/spider/LogUtils.print ()V
看到了吗,它是一个INVOKEVIRTUAL修饰的方法!!,而不是INVOKESTATIC,这意味着什么,就是一个普通的运行时方法呀,只不过通过了INSTANCE对象进行调用!所以虽然kotlin的object修饰类的方法调用很像java的静态方法,但是真相是这一个final static对象调用的一个普通方法罢了!!所以如果有修改字节码or字节码生成的场景下,千万要注意这可是一个INVOKEVIRTUAL方法哟
扩展
那如果我们想在object类生成一个静态方法呢?别急,kotlin早就为你提供啦!方法前添加注解@JvmStatic就可以啦!我们再看一下字节码
GETSTATIC com/example/spider/LogUtils.INSTANCE : Lcom/example/spider/LogUtils;
POP
INVOKESTATIC com/example/spider/LogUtils.print ()V
是不是!最后就变成INVOKESTATIC啦!在java kotlin混编译的时候,kotlin的object类方法加上@JvmStatic就可以当作静态方法愉快使用啦!
最后
如果你想进行字节码插桩,或者hook方法,可以关注一下这篇文章噢!从零编写一个基于gradle的hook框架哟!
link:juejin.cn/post/710008… github:github.com/TestPlanB/S… 快来star一下吧!