伴生对象
kotlin的伴生对象用companion关键字来指定,可以省略伴生对象的名称,伴生对象的成员可通过只使用类名作为限定符来调用,伴生对象的成员看起来像其他语言的静态成员,在运行时他们仍然是真实对象的实例成员。为什么有着静态成员的特性却是真实对象的实例成员呢?
class User {
companion object {
const val tag = "companion"
private val property = "user_companion"
val property2 = "user_companion2"
fun newInstance(): User {
return User()
}
}
}
复制代码
这段代码对应如下java代码
public final class User {
public static final String tag = "companion";
private static final String property = "user_companion";
private static final String property2 = "user_companion2";
public static final User.Companion Companion = new User.Companion((DefaultConstructorMarker)null);
public static final class Companion {
private final String getProperty() {
return User.property;
}
@NotNull
public final String getProperty2() {
return User.property2;
}
@NotNull
public final User newInstance() {
return new User();
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
复制代码
再类里面生成了一个静态的User.Companion对象,这个Companion是在不指定伴生对象类名的情况下的默认名字,用const修饰的常量直接是编译生成public static final对应的常量;其他常量就对应生成private static final对应的常量,并生成其他相应的get方法。
看一下通过类名调用代码以及生成代码
fun main(args: Array<String>) {
println(User.tag)
println(User.property2)
println(User.newInstance())
}
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
String var1 = "companion";
System.out.println(var1);
var1 = User.Companion.getProperty2();
System.out.println(var1);
User var2 = User.Companion.newInstance();
System.out.println(var2);
复制代码
}
一目了然,伴随对象就是生成了一个静态的对象,生成对应的方法,在调用的时候,通过生成的静态对象去代理
内联函数
为什么要内联函数?
调用一个方法是一个压栈和出栈的过程,调用方法时将栈针压入方法栈,然后执行方法体,方法结束时将栈针出栈,这个压栈和出栈的过程会耗费资源,这个过程中传递形参也会耗费资源。
什么是内联函数?
当一个函数被声明为inline时,它的函数体是内联的——换句话说,函数体会被直接替换到函数调用的地方,而不是被正常调用。
我们先写一个函数被正常调用的代码
fun main(args: Array<String>) {
val a = 1
val b = 2
a.calculate(b) { x, y ->
val c = x + y
println(c)
c
}
}
fun Int.calculate(b: Int, calculator: (Int, Int) -> Int): Int {
return calculator(this, b)
}
------------------------
public final class DemoKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
int a = 1;
int b = 2;
calculate(a, b, (Function2)null.INSTANCE);
}
public static final int calculate(int $receiver, int b, @NotNull Function2 calculator) {
Intrinsics.checkParameterIsNotNull(calculator, "calculator");
return ((Number)calculator.invoke(Integer.valueOf($receiver), Integer.valueOf(b))).intValue();
}
}
复制代码
可以看到calculate(a, b, (Function2)null.INSTANCE)其实也就是一个常规方法的调用,我们把calculate函数加上inline
fun main(args: Array<String>) {
val a = 1
val b = 2
a.calculate(b) { x, y ->
val c = x + y
println(c)
c
}
}
inline fun Int.calculate(b: Int, calculator: (Int, Int) -> Int): Int {
return calculator(this, b)
}
----------------------
public final class DemoKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
int a = 1;
int b = 2;
int c = a + b;
System.out.println(c);
}
public static final int calculate(int $receiver, int b, @NotNull Function2 calculator) {
Intrinsics.checkParameterIsNotNull(calculator, "calculator");
return ((Number)calculator.invoke(Integer.valueOf($receiver), Integer.valueOf(b))).intValue();
}
}
复制代码
可以看到main方法中好像就直接把calculate方法中的语句拷贝进去了一样,并没有做函数的调用。这就是内联函数与普通函数的区别。