Scala中的@specialized

为什么需要@specialized

@specialized 是为了解决由于泛型擦除而需要对基础数据类型进行装箱/拆箱操作所带来的性能问题

@specializedscala2.8 开始加入的,为什么要增加呢?

Java/Jvm的泛型是类型擦除的,也就是说泛型编译时会被丢弃,全部向上转型为 Object, 因此对基础数据类型(primitive) 来说, 无法直接使用基础数据类型
作为泛型参数,如 List 是不可以的,所以就有了 BoxUnbox, 将 int 装箱为 Integer , double 装箱为 Double, 等等。

带来的问题是内存的增加, double 本身只需要 8 个字节,装箱为 Double 后,将需要 24 个字节,对于一些有庞大集合的应用来说,很可能会带来内存的
性能瓶颈。

Scala由于需要编译为Java字节码,因此也就继承了Java/JVM这个缺陷,为了改进这个缺陷,Scala增加了 @specialized 注解,来指示Scala编译器来规避这个问题

@specialized 是如何解决的

首先,Scala语言标准库中定义了 specialized 来告知编译器针对泛型进行优化:

class specialized(group: SpecializedGroup) extends scala.annotation.StaticAnnotation {
   def this(types: Specializable*) = this(new Group(types.toList))
   def this() = this(Primitives)
}

其次,针对设置了 @specialized 的泛型类型,Scala编译器会针对特定的基础数据类型生成特定版本的代码,例如:

package eq
import scala.{specialized => sp}
trait Eq[@sp(Int) T] extends Any with Serializable {self =>
   def eqv(x: T, y: T): Boolean
}

scalac -print 进行编译便可看见结果,如果 @sp 不指定类型,则会生成所有基础数据类型的特定版本。

需要注意的问题

固然 @specialized 通过特化版本的方式能够提高性能,但也是有缺点的:

  1. 会产生大量的特化版本的类,导致运行时需要加载更多的类型
  2. 如果有泛型依赖,被依赖中的泛型没有设置 specialized 就算设置了,也不会被特化,因此有一定的局限性

参考资料

  1. Specializing for primitive types
  2. Specialization - Dragos

你可能感兴趣的:(Scala中的@specialized)