从Scala方法返回AnyVal
谁能解释一下为什么会出现以下Scala代码片段:从Scala方法返回AnyVal,scala,Scala,谁能解释一下为什么会出现以下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
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, locals=2, 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, locals=2, 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
}
从“PrimTest.scala”编译而来
公开期末考试$
源文件:“PrimTest.scala”
Scala:length=0x0
次要版本:0
主要版本:50
标志:ACC_PUBLIC、ACC_FINAL、ACC_SUPER
固定池:
#1=Utf8填充/基本测试$
#2=类#1//填充/基本测试$
#3=Utf8 java/lang/Object
#4=类#3//java/lang/Object
#5=Utf8 PrimTest.scala
#6=Utf8模块$
#7=Utf8 Lstuff/PrimTest$;
#8=Utf8
#9=Utf8()V
#10=Utf8
#11=名称和类型#10:#9/“”:()V
#12=Methodref#2.#11//stuff/PrimTest$。“”:()V
#13=Utf8 convertRefToVal
#14=Utf8(Ljava/lang/Object;)I
#15=Utf8 java/lang/Integer
#16=类#15//java/lang/Integer
#17=Utf8 scala/runtime/BoxesRunTime
#18=类#17//scala/runtime/BoxesRunTime
#19=Utf8取消粘贴
#20=NameAndType#19:#14//unextpoint:(Ljava/lang/Object;)I
#21=Methodref#18.#20//scala/runtime/BoxesRunTime.unextpoint:(Ljava/lang/Object;)I
#22=Utf8此
#23=Utf8 obj
#24=Utf8 Ljava/lang/Object;
#25=Utf8转换器参考值1
#26=Utf8(Ljava/lang/Object;)Ljava/lang/Object;
#27=Utf8 boxToInteger
#28=Utf8(I)Ljava/lang/Integer;
#29=名称和类型#27:#28//boxToInteger:(I)Ljava/lang/Integer;
#30=Methodref#18.#29//scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
#31=Utf8主
#32=Utf8([Ljava/lang/String;)V
#33=Utf8(I)V
#34=名称和类型#10:#33/“”:(I)V
#35=Methodref#16.#34//java/lang/Integer.“:(I)V
#36=Utf8参数
#37=Utf8[Ljava/lang/String;
#38=Methodref#4.#11//java/lang/Object.“:()V
#39=名称和类型#6:#7//模块$:Lstuff/PrimTest$;
#40=Fieldref#2.#39//stuff/PrimTest$.MODULE$:Lstuff/PrimTest$;
#41=Utf8代码
#42=Utf8 LocalVariableTable
#43=Utf8行号表
#44=Utf8堆栈映射表
#45=Utf8源文件
#46=Utf8 Scala
{
公共静态final stuff.PrimTest$MODULE$;
标志:ACC_公共、ACC_静态、ACC_最终
公共静态{};
标志:ACC_公共,ACC_静态
代码:
堆栈=1,局部变量=0,参数大小=0
0:new#2//class stuff/PrimTest$
3:invokespecial#12//方法“”:()V
6:返回
public int convertRefToVal(java.lang.Object);
旗帜:ACC_PUBLIC
代码:
堆栈=1,局部变量=2,参数大小=2
0:aload_1
1:instanceof#16//class java/lang/Integer
4:ifeq 14
7:aload_1
8:invokestatic#21//方法scala/runtime/BoxesRunTime.unextpoint:(Ljava/lang/Object;)I
11:goto 15
14:iconst_m1
15:我轮到你了
LocalVariableTable:
起始长度插槽名称签名
0 16 0此Lstuff/PrimTest$;
0 16 1对象Ljava/lang/Object;
LineNumberTable:
第6行:0
第7行:14
第6行:15
StackMapTable:条目数=2
框架类型=14/*相同*/
框架类型=64/*相同的局部变量1堆栈项*/
堆栈=[int]
public java.lang.Object convertRefToVal1(java.lang.Object);
旗帜:ACC_PUBLIC
代码:
堆栈=1,局部变量=2,参数大小=2
0:aload_1
1:instanceof#16//class java/lang/Integer
scala> :implicits -v
...
implicit def Integer2int(x: jl.Integer): Int
...
scala> val ji: java.lang.Integer = 1
ji: java.lang.Integer = 1
scala> val si: Int = ji // here the implicit conversion is taking place
si: Int = 1
scala> ji.getClass()
res4: java.lang.Class[_ <: java.lang.Integer] = class java.lang.Integer
scala> si.getClass()
res5: java.lang.Class[Int] = int
scala> Integer2int(ji)
res6: Int = 1
scala> Integer2int(ji).getClass // calling it explicitly
res7: java.lang.Class[Int] = int