可以编译以下代码而不会出错。
val a: Int = 1
val b = a.asInstanceOf[AnyRef]
这使我感到困惑,因为Int扩展了AnyVal,它不是子类,而是AnyRef的兄弟。
但是,如果按照以下方式使用归属:
val a: Int = 1
val b: AnyRef = a
它不起作用。
error: type mismatch;
found : Int
required: AnyRef
Note: an implicit exists from scala.Int => java.lang.Integer, but
methods inherited from Object are rendered ambiguous. This is to avoid
a blanket implicit which would convert any scala.Int to any AnyRef.
You may wish to use a type ascription: `x: java.lang.Integer`.
val b: AnyRef = a
我的理解:
asInstanceOf
在运行时执行,它迫使编译器相信val a是AnyRef。
但是,归档是在编译时,转换无法通过类型检查,因此我们遇到“类型不匹配”错误。
我的问题:
答案 0 :(得分:5)
这是因为自动装箱:
scala>val a: Int = 1
a: Int = 1
scala> a.getClass
res2: Class[Int] = int
scala> val b = a.asInstanceOf[AnyRef]
b: AnyRef = 1
scala> b.getClass
res1: Class[_ <: AnyRef] = class java.lang.Integer
通过强制转换为AnyRef
(java.lang.Object
),触发从int到java.lang.Integer的自动装箱
如果在JVM中将AnyRef视为
java.lang.Object
,那么AnyVal
怎么样? 它是运行时的对象吗?
AnyRef
确实是java.lang.Object
的别名
AnyVal
是一个&#34;虚拟&#34;类型,它只在编译时存在,以便类型系统完整。
在运行时,扩展AnyVal
的实例将转换为相应的本机类型(int
,double
等),String
转到java.lang.String
除外它本身扩展java.lang.Object
但在JVM中有特殊处理。
但是
AnyVal
是AnyRef
的兄弟姐妹,不是吗?)
AnyVal
和AnyRef
都扩展了Any
类型,但它们并没有相互延伸。
scala编译器是否有一些技巧?
加载:)
有关Scala类型层次结构的更完整说明,建议您先阅读:http://docs.scala-lang.org/tutorials/tour/unified-types.html
答案 1 :(得分:4)
补充“因为自动装箱”,你可以观察到使用了什么魔法。
-Xprint:all
将显示哪个编译器阶段完成了魔术。
-Ytyper-debug
显示了由typer做出的决定。
例如,在给定val a: Int
的情况下,val b = a.isInstanceOf[AnyRef]
在擦除时更改为Int.box(a).$asInstanceOf[Object]
,其中$asInstanceOf
是Object
的名义成员。
关于这些转换in erasure:
有一个很好的评论/** Replace member references as follows:
*
* - `x == y` for == in class Any becomes `x equals y` with equals in class Object.
* - `x != y` for != in class Any becomes `!(x equals y)` with equals in class Object.
* - x.asInstanceOf[T] becomes x.$asInstanceOf[T]
* - x.isInstanceOf[T] becomes x.$isInstanceOf[T]
* - x.isInstanceOf[ErasedValueType(tref)] becomes x.isInstanceOf[tref.sym.tpe]
* - x.m where m is some other member of Any becomes x.m where m is a member of class Object.
* - x.m where x has unboxed value type T and m is not a directly translated member of T becomes T.box(x).m
* - x.m where x is a reference type and m is a directly translated member of value type T becomes x.TValue().m
* - All forms of x.m where x is a boxed type and m is a member of an unboxed class become
* x.m where m is the corresponding member of the boxed class.
*/
相比之下,OP的错误消息中提到的归因引起的转换是因为隐含在Predef
中而发生的:
scala> val I: java.lang.Integer = a
[[syntax trees at end of typer]] // <console>
private[this] val I: Integer = scala.this.Predef.int2Integer($line3.$read.$iw.$iw.a);