首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么在Scala中AnyVal可以在运行时转换为AnyRef?

为什么在Scala中AnyVal可以在运行时转换为AnyRef?
EN

Stack Overflow用户
提问于 2014-09-19 10:17:40
回答 2查看 2.6K关注 0票数 7

可以编译以下代码,而不会出现错误。

代码语言:javascript
复制
val a: Int = 1
val b = a.asInstanceOf[AnyRef]

这让我感到困惑,因为Int扩展了AnyVal,它不是一个子类,而是AnyRef的同级。

但是,如果归属如下:

代码语言:javascript
复制
val a: Int = 1
val b: AnyRef = a

它不起作用。

代码语言:javascript
复制
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是AnyRef。然而,一个归属是在编译时,转换不能通过类型检查,所以我们有一个“类型错配”错误。

我的问题:

  1. 基本上,为什么转换在运行时工作?
  2. 如果AnyRef在JVM中被认为是java.lang.Object,那么AnyVal如何?在运行时它是一个对象吗?
    • (如果是,它的类型是什么?java.lang.Object?但AnyVal是AnyRef的兄弟姐妹,不是吗?)
    • (如果不是,我们如何使用AnyVal的一些子类作为对象,比如Int,Double)
    • scala编译器有什么花招吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-09-19 12:01:10

这是因为自动装箱:

代码语言:javascript
复制
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的自动装箱

如果AnyRef在JVM中被认为是java.lang.Object,那么AnyVal如何?在运行时它是一个对象吗?

AnyRef确实是一个别名,因为java.lang.Object AnyVal是一个“虚拟”类型,它只存在于编译时,是为了类型系统的完整性。

在运行时,扩展AnyVal的实例被转换为相应的本机类型(intdouble等),但String除外,后者本身扩展了java.lang.Object,但在JVM中有特殊的处理。

AnyValAnyRef的兄弟姐妹,不是吗?)

AnyValAnyRef都扩展了Any类型,但它们并不相互扩展。

scala编译器有什么花招吗?

负载:)

要更完整地解释Scala类型的等级,我建议您先阅读:http://docs.scala-lang.org/tutorials/tour/unified-types.html

票数 8
EN

Stack Overflow用户

发布于 2014-09-19 15:59:29

作为“自动拳击”的补充,您可以观察到使用了什么魔法。

-Xprint:all将展示哪个编译器阶段发挥了神奇的作用。

-Ytyper-debug显示了typer所做的决定。

例如,给定val a: Int,则val b = a.isInstanceOf[AnyRef]在擦除中更改为Int.box(a).$asInstanceOf[Object],其中$asInstanceOfObject的名义成员。

关于这些转换,擦除有一个很好的注释

代码语言:javascript
复制
/**  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中的隐式

代码语言:javascript
复制
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);
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25931611

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档