值类型(Value class)是一种通过继承 AnyVal 类来避免运行时对象分配的新机制。
值类型
创建
以下是一个最简单的值类型
class Wrapper(val underlying: Int) extends AnyVal
它仅有一个被用作运行时底层表示的公有val参数。在编译期,其类型为 Wrapper,但在运行时,它被表示为一个 Int。
值类型可以带有def定义,但不能再定义额外的val、var,以及内嵌的trait、class或object
继承
值类型只能继承普通 trait,但其自身不能再被继承。
普通 trait就是继承自 Any 的、只有
def成员,且不作任何初始化工作的 trait
继承自某个普通 trait 的值类型同时继承了该 trait 的方法,但是(调用这些方法)会带来一定的对象分配开销。
trait Printable extends Any {
def print(): Unit = println(this)
}
class Wrapper(val underlying: Int) extends AnyVal with Printable
val w = new Wrapper(3)
w.print() // 这里实际上会生成一个Wrapper类的实例
用例
扩展方法
值类型可以和隐式类配合用来为类添加扩展方法,并且避免额外的内存开销。
implicit class RichInt(val self: Int) extends AnyVal {
def toHexString: String = java.lang.Integer.toHexString(self)
}
在运行时,表达式3.toHexString被优化并等价于静态对象的方法调用RichInt$.MODULE$.extension$toHexString(3),而不是创建一个新实例对象,再调用其方法。
确保类型安全
可以额外定义一个值类型用来保证类型安全。
class Meter(val value: Double) extends AnyVal {
def +(m: Meter): Meter = new Meter(value + m.value)
}
val x = new Meter(3.4)
val y = new Meter(4.3)
val z = x + y
实际上不会分配任何 Meter 实例,而是在运行时仅使用原始双精浮点数(double) 。
总结
值类型用于减少内存分配消耗,我们在编程中可以灵活使用提高程序性能。
聊一聊
想法、问题,或不同的解法,都欢迎留下来。使用 GitHub 账号参与讨论。