从Scala方法返回AnyVal
任何人都可以解释为什么下面的
Scala代码片段:
def convertRefToVal(obj: Any): Int = { if (obj.isInstanceOf[java.lang.Integer]) obj.asInstanceOf[Int] else -1 } convertRefToVal(42).getClass() 打印java.lang.Class [Int] = int,而这个: def convertRefToVal(obj: Any): AnyVal = { if (obj.isInstanceOf[java.lang.Integer]) obj.asInstanceOf[Int] else -1 } convertRefToVal(42).getClass() 生成java.lang.Class [_] = class java.lang.Integer? 除了返回类型(Int与AnyVal)之外,这些方法是相同的. 所以第一个例子返回一个Int值类型,而在第二个例子中,我得到一个java.lang.Integer引用类型作为结果.它看起来像自动装箱正在发生,但我不希望这看到第二个版本指定AnyVal作为其返回类型? (我正在使用Scala 2.10.2) 解决方法
实际上,在两个版本中,在函数的入口点都应用了自动装箱,可能是因为obj需要是Any.但有趣的是,当你考虑类型时:
def convertRefToVal(obj: Any): Int = { println(obj.isInstanceOf[java.lang.Integer]) println(obj.isInstanceOf[Int]) println(obj.getClass()) if (obj.isInstanceOf[java.lang.Integer]) obj.asInstanceOf[Int] else -1 } convertRefToVal(42) 这打印: true true class java.lang.Integer 所以一个问题是java.lang.Integer在任何情况下都被认为是Int的一个实例. 无论如何,看起来Scala具有特定的支持,可以根据返回类型从包装器“转换”为基元.我将尝试在我的问题中找到答案,并编辑它. 编辑:其他人可能会提供历史原因,但这是一个事实.这是javap为这两个函数打印的内容: public int convertRefToVal(java.lang.Object); //first version public java.lang.Object convertRefToVal1(java.lang.Object); //second version 因此,正如您所看到的,AnyVal从长远来看映射到java.lang.Object.实际上,这些函数之间的区别在于,虽然两者都取消了先前自动装箱的参数,但第二个将其再次装箱. 为了演示,这是一个示例类: package stuff object PrimTest { def convertRefToVal(obj: Any): Int = { if (obj.isInstanceOf[java.lang.Integer]) obj.asInstanceOf[Int] else -1 } def convertRefToVal1(obj: Any): AnyVal = { if (obj.isInstanceOf[java.lang.Integer]) obj.asInstanceOf[Int] else -1 } def main(args: Array[String]): Unit = { new java.lang.Integer(42).asInstanceOf[Int] //added for isolating the cast example } } 这是java -p -v输出: Compiled from "PrimTest.scala" public final class stuff.PrimTest$ SourceFile: "PrimTest.scala" Scala: length = 0x0 minor version: 0 major version: 50 flags: ACC_PUBLIC,ACC_FINAL,ACC_SUPER Constant pool: #1 = Utf8 stuff/PrimTest$ #2 = Class #1 // stuff/PrimTest$ #3 = Utf8 java/lang/Object #4 = Class #3 // java/lang/Object #5 = Utf8 PrimTest.scala #6 = Utf8 MODULE$ #7 = Utf8 Lstuff/PrimTest$; #8 = Utf8 <clinit> #9 = Utf8 ()V #10 = Utf8 <init> #11 = NameAndType #10:#9 // "<init>":()V #12 = Methodref #2.#11 // stuff/PrimTest$."<init>":()V #13 = Utf8 convertRefToVal #14 = Utf8 (Ljava/lang/Object;)I #15 = Utf8 java/lang/Integer #16 = Class #15 // java/lang/Integer #17 = Utf8 scala/runtime/BoxesRunTime #18 = Class #17 // scala/runtime/BoxesRunTime #19 = Utf8 unboxToInt #20 = NameAndType #19:#14 // unboxToInt:(Ljava/lang/Object;)I #21 = Methodref #18.#20 // scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I #22 = Utf8 this #23 = Utf8 obj #24 = Utf8 Ljava/lang/Object; #25 = Utf8 convertRefToVal1 #26 = Utf8 (Ljava/lang/Object;)Ljava/lang/Object; #27 = Utf8 boxToInteger #28 = Utf8 (I)Ljava/lang/Integer; #29 = NameAndType #27:#28 // boxToInteger:(I)Ljava/lang/Integer; #30 = Methodref #18.#29 // scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer; #31 = Utf8 main #32 = Utf8 ([Ljava/lang/String;)V #33 = Utf8 (I)V #34 = NameAndType #10:#33 // "<init>":(I)V #35 = Methodref #16.#34 // java/lang/Integer."<init>":(I)V #36 = Utf8 args #37 = Utf8 [Ljava/lang/String; #38 = Methodref #4.#11 // java/lang/Object."<init>":()V #39 = NameAndType #6:#7 // MODULE$:Lstuff/PrimTest$; #40 = Fieldref #2.#39 // stuff/PrimTest$.MODULE$:Lstuff/PrimTest$; #41 = Utf8 Code #42 = Utf8 LocalVariableTable #43 = Utf8 LineNumberTable #44 = Utf8 StackMapTable #45 = Utf8 SourceFile #46 = Utf8 Scala { public static final stuff.PrimTest$MODULE$; flags: ACC_PUBLIC,ACC_STATIC,ACC_FINAL public static {}; flags: ACC_PUBLIC,ACC_STATIC Code: stack=1,locals=0,args_size=0 0: new #2 // class stuff/PrimTest$ 3: invokespecial #12 // Method "<init>":()V 6: return public int convertRefToVal(java.lang.Object); flags: ACC_PUBLIC Code: stack=1,locals=2,args_size=2 0: aload_1 1: instanceof #16 // class java/lang/Integer 4: ifeq 14 7: aload_1 8: invokestatic #21 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I 11: goto 15 14: iconst_m1 15: ireturn LocalVariableTable: Start Length Slot Name Signature 0 16 0 this Lstuff/PrimTest$; 0 16 1 obj Ljava/lang/Object; LineNumberTable: line 6: 0 line 7: 14 line 6: 15 StackMapTable: number_of_entries = 2 frame_type = 14 /* same */ frame_type = 64 /* same_locals_1_stack_item */ stack = [ int ] public java.lang.Object convertRefToVal1(java.lang.Object); flags: ACC_PUBLIC Code: stack=1,args_size=2 0: aload_1 1: instanceof #16 // class java/lang/Integer 4: ifeq 17 7: aload_1 8: invokestatic #21 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I 11: invokestatic #30 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer; 14: goto 21 17: iconst_m1 18: invokestatic #30 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer; 21: areturn LocalVariableTable: Start Length Slot Name Signature 0 22 0 this Lstuff/PrimTest$; 0 22 1 obj Ljava/lang/Object; LineNumberTable: line 11: 0 line 12: 17 line 11: 21 StackMapTable: number_of_entries = 2 frame_type = 17 /* same */ frame_type = 67 /* same_locals_1_stack_item */ stack = [ class java/lang/Integer ] public void main(java.lang.String[]); flags: ACC_PUBLIC Code: stack=3,args_size=2 0: new #16 // class java/lang/Integer 3: dup 4: bipush 42 6: invokespecial #35 // Method java/lang/Integer."<init>":(I)V 9: invokestatic #21 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I 12: pop 13: return LocalVariableTable: Start Length Slot Name Signature 0 14 0 this Lstuff/PrimTest$; 0 14 1 args [Ljava/lang/String; LineNumberTable: line 16: 0 private stuff.PrimTest$(); flags: ACC_PRIVATE Code: stack=1,locals=1,args_size=1 0: aload_0 1: invokespecial #38 // Method java/lang/Object."<init>":()V 4: aload_0 5: putstatic #40 // Field MODULE$:Lstuff/PrimTest$; 8: return LocalVariableTable: Start Length Slot Name Signature 0 9 0 this Lstuff/PrimTest$; LineNumberTable: line 3: 0 } 注意BoxesRunTime调用的用法,它实际上是一个Java类BTW.这表明编译器中可能存在一些添加这些调用的特定代码. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |