如果我有这个值类:
class ActionId(val value: Int) extends AnyVal
那么,在下面的所有示例中,都会为值类分配一个对象吗? (它将被“装箱”——它将not只需将其解包为普通的 32 位整数,对吧?)
-
返回值类的函数 - 值类逃逸范围并因此被“装箱”?
def someFunction(): ActionId = {
...
return ActionId(123)
}
-
一个返回的函数具有值类成员的对象— 值类脱离了范围并因此被“装箱”?
case class Post(id: ActionId, ...) { ... }
def someFunction(): Post = {
...
val somePost = Post(ActionId(123), ...) // ActionId will be "boxed", right?
return somePost
}
-
Even if 具有值类成员的对象 is not返回(并没有真正逃脱范围),当值类用作另一个类的成员(作为Post
类,在本例中)?
def anotherFunction() {
...
val somePost = Post(ActionId(123), ...) // "Boxed" here too, right?
// ... do something with somePost
// But don't: return somePost
// However some *other* similar functions *do* return `somePost` — so
// class `Post` must be able to box the ActionId? Hence it's boxed (above)?
}
与此相关的是这个答案,这说明了当值类没有逃逸范围时,它实际上被内联了。参考Scala Improvement Process文档SIP-15更多细节。然而,据我所知,SIP-15 实际上并没有提到逃逸范围的值类实例将被“装箱”。但我认为它必须被“装箱”似乎是合理的。 (为什么SIP没有明确说明如果逃逸就会被装箱?)
你的例子都没有导致拳击。值类仅与泛型、数组一起装箱,并且当键入为超类/特征时(例如 Any/AnyVal)
它们用泛型装箱,否则你无法将它们与值区分开来(而且基元无论如何都需要一个盒子)。 Any 也同样处理,其他超类/特征需要一个框,否则类型关系是错误的。
它们用数组装箱,因为数组需要知道内容的类型,但 JVM 不理解“值类型”的概念。所以你最终会得到一个数组,它表示它是被装箱的类型,但 Scala 假装是值类型的数组;我们做出了一个决定(基于之前 Array 的问题,当时它不仅仅是一个普通的 Java/JVM 数组),这将导致太多微妙的错误和极端情况。
以下是获得拳击的三种方法的示例:
trait Q extends Any {}
class X(val x: String) extends AnyVal with Q {}
// Array
val a = Array(new X("salmon")) // boxed
// Generic
val b = Option(new X("minnow")) // boxed
// Upcast
val c = (new X("perch"): Any) // boxed
val d = (new X("cod"): AnyVal) // boxed
val e = (new X("herring"): Q) // boxed
其他所有内容(通过各种函数等传递)都不需要装箱,包括您的所有示例。
数组是一种特殊情况,因为您可以存储基元并将它们作为值类再次取出,字节码开销为零,但语法开销很大:
class Y(val repr: String) extends AnyVal {}
val y1 = new Y("apple") // unboxed
val y2 = new Y("orange") // unboxed
val ys: Array[String] = Array(y1.repr, y2.repr) // no overhead
val y3 = new Y(ys(0)) // no overhead
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)