Scala闭包如何转换为Java对象?
我目前正在用不同的语言来看封闭实现。但是,当涉及Scala时,我无法找到关于闭包如何映射到Java对象的任何文档。
有很好的记录,Scala函数映射到FunctionN对象。我认为对该闭包的自由变量的引用必须存储在该函数对象的某处(如在C 0x中完成的)。 我还尝试用scalac编译以下内容,然后用JD反编译类文件: object ClosureExample extends Application { def addN(n: Int) = (a: Int) => a + n var add5 = addN(5) println(add5(20)) } 在反编译的源代码中,我看到一个名为Function1的匿名子类型,它应该是我的关闭。但是apply()方法是空的,匿名类没有字段(可能存储闭包变量)。我想反编译器没有设法从类文件中获取有趣的部分… 现在问题: >你知道转型是如何完成的? 解决方法
让我们分开一个例子,以便我们看到它们有什么区别。 (如果使用RC1,请使用-no-specialization进行编译,以使事情更容易理解。)
class Close { var n = 5 def method(i: Int) = i+n def function = (i: Int) => i+5 def closure = (i: Int) => i+n def mixed(m: Int) = (i: Int) => i+m } 首先,我们来看看什么方法: public int method(int); Code: 0: iload_1 1: aload_0 2: invokevirtual #17; //Method n:()I 5: iadd 6: ireturn 很简单这是一种方法。加载参数,调用n,add,return的getter。看起来就像Java。 功能怎么样?它实际上并没有关闭任何数据,但它是一个匿名函数(称为Close $$ anonfun $ function $ 1)。如果我们忽略任何专业化,构造函数和应用程序是最有意义的: public scala.Function1 function(); Code: 0: new #34; //class Close$$anonfun$function$1 3: dup 4: aload_0 5: invokespecial #35; //Method Close$$anonfun$function$1."<init>":(LClose;)V 8: areturn public Close$$anonfun$function$1(Close); Code: 0: aload_0 1: invokespecial #43; //Method scala/runtime/AbstractFunction1."<init>":()V 4: return public final java.lang.Object apply(java.lang.Object); Code: 0: aload_0 1: aload_1 2: invokestatic #26; //Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I 5: invokevirtual #28; //Method apply:(I)I 8: invokestatic #32; //Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer; 11: areturn public final int apply(int); Code: 0: iload_1 1: iconst_5 2: iadd 3: ireturn 所以,你加载一个“this”指针并创建一个新的对象,它以封闭类作为参数。这是任何内部类的标准,真的。该函数不需要对外部类执行任何操作,因此只需调用super的构造函数即可。然后,当调用应用程序时,你会执行box / unbox技巧,然后调用实际的数学 – 也就是添加5。 但是如果我们使用关闭中的变量关闭怎么办?安装程序是完全一样的,但是现在的构造函数Close $$ anonfun $ closure $ 1看起来像这样: public Close$$anonfun$closure$1(Close); Code: 0: aload_1 1: ifnonnull 12 4: new #48; //class java/lang/NullPointerException 7: dup 8: invokespecial #50; //Method java/lang/NullPointerException."<init>":()V 11: athrow 12: aload_0 13: aload_1 14: putfield #18; //Field $outer:LClose; 17: aload_0 18: invokespecial #53; //Method scala/runtime/AbstractFunction1."<init>":()V 21: return 也就是说,它检查以确保输入不为空(即外部类不为空)并将其保存在字段中。现在应用它的时候,拳击/拆箱包装后: public final int apply(int); Code: 0: iload_1 1: aload_0 2: getfield #18; //Field $outer:LClose; 5: invokevirtual #24; //Method Close.n:()I 8: iadd 9: ireturn 你看到它使用该字段引用父类,并为n调用getter。添加,返回,完成。所以,闭包很容易:匿名函数构造函数只是将封闭类保存在私有字段中。 现在,如果我们关闭不是内部变量,而是关闭方法参数呢?这就是Close $ anonfun $ mixed $ 1。首先,看一下混合方法的作用: public scala.Function1 mixed(int); Code: 0: new #39; //class Close$$anonfun$mixed$1 3: dup 4: aload_0 5: iload_1 6: invokespecial #42; //Method Close$$anonfun$mixed$1."<init>":(LClose;I)V 9: areturn 在调用构造函数之前加载参数m!所以构造函数看起来像这样,这并不奇怪: public Close$$anonfun$mixed$1(Close,int); Code: 0: aload_0 1: iload_2 2: putfield #18; //Field m$1:I 5: aload_0 6: invokespecial #43; //Method scala/runtime/AbstractFunction1."<init>":()V 9: return 其中该参数保存在私有字段中。由于我们不需要外部类,所以没有提及外部类。你应该不会感到惊讶: public final int apply(int); Code: 0: iload_1 1: aload_0 2: getfield #18; //Field m$1:I 5: iadd 6: ireturn 是的,我们只是加载这个存储的字段并做我们的数学。 我不知道你在做什么,没有看到这个例子 – 对象有点棘手,因为他们有MyObject和MyObject $类,并且方法在两个之间分裂,可能不直观。但是应用绝对适用于事物,整个系统的工作原理与您期望的方式相似(在您坐下来,在很长一段时间内真的很难想像)。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |