为什么此代码无法运行,这是Kotlin中的错误吗?

时间:2019-11-10 07:00:36

标签: kotlin lambda classnotfoundexception

我写了一段代码,然后编译没有错误。但是当我运行时,它会引发异常(java.lang.NoClassDefFoundError:TesKt $ test $ 1 $ 1)。

这是语言错误吗?

private fun test(block:()->Unit) = arrayOf(1).map {

    object {

        fun print() {
            println("Hello print")
            block()
        }
    }
}

fun main(args: Array<String>) {
    val array = test{println("Hello main")}
    array[0].print()
}

1 个答案:

答案 0 :(得分:2)

我将得出结论,这是Kotlin编译器中的错误。我在这段代码中发挥了很多作用,并查看了编译后的字节码。似乎编译器正在丢失有关object定义的匿名类的某些信息。

如果我们向该对象添加类型,则可以正常工作:

interface Printable {
    fun print()
}

private fun test(block:()->Unit): List<Printable> {
    return arrayOf(1).map {

        object: Printable {

            override fun print() {
                println("Hello print")
                block()
            }
        }
    }
}

fun main(args: Array<String>) {
    val array = test{println("Hello main")}
    array[0].print()
}

如您所见,我仅定义了一个简单的Printable接口,并使用该接口对匿名类进行了注释。

我们将您的代码称为A版,并将我的代码称为B版。

我编译了代码A,然后反编译为Java。结果如下:

import TestKt.test.1.1;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import kotlin.Metadata;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = {1, 1, 15},
   bv = {1, 0, 3},
   k = 2,
   d1 = {"\u0000#\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0011\n\u0002\u0010\u000e\n\u0002\b\u0002\n\u0002\u0010 \n\u0002\b\u0002\n\u0002\u0018\u0002*\u0001\b\u001a\u0019\u0010\u0000\u001a\u00020\u00012\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003¢\u0006\u0002\u0010\u0005\u001a\u001c\u0010\u0006\u001a\b\u0012\u0004\u0012\u00020\b0\u00072\f\u0010\t\u001a\b\u0012\u0004\u0012\u00020\u00010\nH\u0002"},
   d2 = {"main", "", "args", "", "", "([Ljava/lang/String;)V", "test", "", "TestKt$test$1$1", "block", "Lkotlin/Function0;"}
)
public final class TestKt {
/*#19:*/private static final List<1> test(Function0<Unit> block) {
      Object[] $this$map$iv = new Integer[]{1};
      int $i$f$map = false;
      Collection destination$iv$iv = (Collection)(new ArrayList($this$map$iv.length));
      int $i$f$mapTo = false;
      Integer[] var6 = $this$map$iv;
      int var7 = $this$map$iv.length;

      for(int var8 = 0; var8 < var7; ++var8) {
         Object item$iv$iv = var6[var8];
         int it = ((Number)item$iv$iv).intValue();
         int var11 = false;
/*#31:*/ TestKt.test..inlined.map.lambda.1 var13 = new TestKt.test..inlined.map.lambda.1(block);
         destination$iv$iv.add(var13);
      }

      return (List)destination$iv$iv;
   }

   public static final void main(@NotNull String[] args) {
      Intrinsics.checkParameterIsNotNull(args, "args");
      List array = test((Function0)TestKt.main.array.1.INSTANCE);
/*#41:*/((1)array.get(0)).print();
   }
}

这是对代码B进行相同处理的结果:

import TestKt.test..inlined.map.lambda.1;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import kotlin.Metadata;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = {1, 1, 15},
   bv = {1, 0, 3},
   k = 2,
   d1 = {"\u0000\"\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0011\n\u0002\u0010\u000e\n\u0002\b\u0002\n\u0002\u0010 \n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\u001a\u0019\u0010\u0000\u001a\u00020\u00012\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003¢\u0006\u0002\u0010\u0005\u001a\u001c\u0010\u0006\u001a\b\u0012\u0004\u0012\u00020\b0\u00072\f\u0010\t\u001a\b\u0012\u0004\u0012\u00020\u00010\nH\u0002"},
   d2 = {"main", "", "args", "", "", "([Ljava/lang/String;)V", "test", "", "LPrintable;", "block", "Lkotlin/Function0;"}
)
public final class TestKt {
/*#19:*/private static final List<Printable> test(Function0<Unit> block) {
      Object[] $this$map$iv = new Integer[]{1};
      int $i$f$map = false;
      Collection destination$iv$iv = (Collection)(new ArrayList($this$map$iv.length));
      int $i$f$mapTo = false;
      Integer[] var6 = $this$map$iv;
      int var7 = $this$map$iv.length;

      for(int var8 = 0; var8 < var7; ++var8) {
         Object item$iv$iv = var6[var8];
         int it = ((Number)item$iv$iv).intValue();
         int var11 = false;
/*#31:*/ 1 var13 = new 1(block);
         destination$iv$iv.add(var13);
      }

      return (List)destination$iv$iv;
   }

   public static final void main(@NotNull String[] args) {
      Intrinsics.checkParameterIsNotNull(args, "args");
      List array = test((Function0)TestKt.main.array.1.INSTANCE);
/*#41:*/((Printable)array.get(0)).print();
   }
}

如您所见,唯一的区别在于第一行以及行号19、31和41(注释为#19:等)。

在代码A中,应该(奇怪地)使用名称为1的类型。但是找不到打包为1的这种类型TestKt.test.1.1,因此您遇到了错误(NoClassDefFoundError: TesKt$test$1$1)。

客栈代码B,但是期望并找到更清晰的Printable类型。

如果编译器像代码AB而不是import TestKt.test..inlined.map.lambda.1;)一样编译了代码的第一行import TestKt.test.1.1;,那么您的代码就可以了。