Kotlin反编译器生成null的原因.例如



我试图通过检查Kotlin在Java端的外观来了解它的一些特性。

因此,作为一个实验,我尝试了这个:

val printKotlin = fun () {
print("Hello Kotlin")
}

所以上面片段的输出是:

public final class FunAsVariableKt {
private static final Function0 printKotlin;
public static final Function0 getPrintKotlin() {
return printKotlin;
}
static {
printKotlin = (Function0)null.INSTANCE;
}
}

如何理解上述反编译代码的静态块?为什么它生成这个不起作用的代码?

使用Kotlin字节码检查器来查看生成的JVM字节码,而不是试图将字节码反编译为Java,这可能不适用于其他语言编译器生成的代码,因为它可能不遵循预期的模式。字节码反编译器并不总是生成工作代码。

JVM字节码!=特定于Java语言的

Kotlin生成的JVM字节码!=Java生成的JVM字节码

您看到的NULL实例被反编译器误解了,您可以看到字节码中对INSTANCE的所有引用都正确设置了值。

这是实际输出:

// ================Stackoverflow_53384931Kt.class =================
// class version 52.0 (52)
// access flags 0x31
public final class Stackoverflow_53384931Kt {

// access flags 0x1A
// signature Lkotlin/jvm/functions/Function0<Lkotlin/Unit;>;
// declaration: kotlin.jvm.functions.Function0<kotlin.Unit>
private final static Lkotlin/jvm/functions/Function0; printKotlin
@Lorg/jetbrains/annotations/NotNull;() // invisible
// access flags 0x19
// signature ()Lkotlin/jvm/functions/Function0<Lkotlin/Unit;>;
// declaration: kotlin.jvm.functions.Function0<kotlin.Unit> getPrintKotlin()
public final static getPrintKotlin()Lkotlin/jvm/functions/Function0;
@Lorg/jetbrains/annotations/NotNull;() // invisible
L0
LINENUMBER 3 L0
GETSTATIC Stackoverflow_53384931Kt.printKotlin : Lkotlin/jvm/functions/Function0;
ARETURN
L1
MAXSTACK = 1
MAXLOCALS = 0
// access flags 0x8
static <clinit>()V
L0
LINENUMBER 3 L0
GETSTATIC Stackoverflow_53384931Kt$printKotlin$1.INSTANCE : LStackoverflow_53384931Kt$printKotlin$1;
CHECKCAST kotlin/jvm/functions/Function0
PUTSTATIC Stackoverflow_53384931Kt.printKotlin : Lkotlin/jvm/functions/Function0;
RETURN
MAXSTACK = 1
MAXLOCALS = 0
@Lkotlin/Metadata; ... 
// access flags 0x18
final static INNERCLASS Stackoverflow_53384931Kt$printKotlin$1 null null
// compiled from: stackoverflow-53384931.kt
}

// ================Stackoverflow_53384931Kt$printKotlin$1.class =================
// class version 52.0 (52)
// access flags 0x30
// signature Lkotlin/jvm/internal/Lambda;Lkotlin/jvm/functions/Function0<Lkotlin/Unit;>;
// declaration: Stackoverflow_53384931Kt$printKotlin$1 extends kotlin.jvm.internal.Lambda implements kotlin.jvm.functions.Function0<kotlin.Unit>
final class Stackoverflow_53384931Kt$printKotlin$1 extends kotlin/jvm/internal/Lambda  implements kotlin/jvm/functions/Function0  {

// access flags 0x1041
public synthetic bridge invoke()Ljava/lang/Object;
ALOAD 0
INVOKEVIRTUAL Stackoverflow_53384931Kt$printKotlin$1.invoke ()V
GETSTATIC kotlin/Unit.INSTANCE : Lkotlin/Unit;
ARETURN
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x11
public final invoke()V
L0
LINENUMBER 4 L0
LDC "Hello Kotlin"
ASTORE 1
L1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 1
INVOKEVIRTUAL java/io/PrintStream.print (Ljava/lang/Object;)V
L2
L3
LINENUMBER 5 L3
RETURN
L4
LOCALVARIABLE this LStackoverflow_53384931Kt$printKotlin$1; L0 L4 0
MAXSTACK = 2
MAXLOCALS = 2
// access flags 0x0
<init>()V
ALOAD 0
ICONST_0
INVOKESPECIAL kotlin/jvm/internal/Lambda.<init> (I)V
RETURN
MAXSTACK = 2
MAXLOCALS = 1
// access flags 0x19
public final static LStackoverflow_53384931Kt$printKotlin$1; INSTANCE
// access flags 0x8
static <clinit>()V
NEW Stackoverflow_53384931Kt$printKotlin$1
DUP
INVOKESPECIAL Stackoverflow_53384931Kt$printKotlin$1.<init> ()V
PUTSTATIC Stackoverflow_53384931Kt$printKotlin$1.INSTANCE : LStackoverflow_53384931Kt$printKotlin$1;
RETURN
MAXSTACK = 2
MAXLOCALS = 0
@Lkotlin/Metadata; ...
OUTERCLASS Stackoverflow_53384931Kt null
// access flags 0x18
final static INNERCLASS Stackoverflow_53384931Kt$printKotlin$1 null null
// compiled from: stackoverflow-53384931.kt
// debug info: SMAP
...
}

您可以为此使用JD-GUI。

http://java-decompiler.github.io/

与用于反编译的内置IntelliJ插件相比,这对我来说效果更好。您只需要将*.class文件提供给它。

Kotlin代码

//TryingOutLamdas.kt
class TryingOutLambdas {
public fun performSomething()
{
takingAOnclickListener { x -> print("Hello $x").toString() }
}

fun takingAOnclickListener(onClickListener: (Int) -> (String))
{
onClickListener.invoke(6)
}
} 

使用JD-GUI为此转换了字节码。

public final class TryingOutLambdas {

public final void performSomething() {

takingAOnclickListener(TryingOutLambdas$performSomething$1
.INSTANCE);
}
public final void takingAOnclickListener(@NotNull Function1 onClickListener) {
Intrinsics.checkParameterIsNotNull(onClickListener, "onClickListener");
onClickListener.invoke(Integer.valueOf(6));
}
static final class TryingOutLambdas$performSomething$1 extends Lambda implements Function1<Integer, String> {
public static final TryingOutLambdas$performSomething$1 INSTANCE = new TryingOutLambdas$performSomething$1();

@NotNull
public final String invoke(int x) {
String str = "Hello " + x;
boolean bool = false;
System.out.print(str);
return Unit.INSTANCE.toString();
}

TryingOutLambdas$performSomething$1() {
super(1);
}
} 
} 

如果lambda表达式访问其声明的函数中的任何变量,则将创建一个实现该接口的新对象,而不是创建上面创建的Singleton实例。

相关内容

  • 没有找到相关文章

最新更新