Annotation是一种对程序代码进行描述的结构化信息。Annotation可以分布在程序的任何地方,能够注解变量、类、方法、参数等多种元素,它的主要功能有以下几种:
1. 自动生成scala文档
2. 检查程序中可能出现的语法问题
3. 规定程序行为
注解的常用场景包括volatile,transient,native,SerialVersionUID,serializable5个,用于对变量或方法进行注解,其中volatile用于标识变量可能会被多个线程同时修改,它不是线程安全的;transient用于标识变量是瞬时的,它不会被持久化;native用于标识算法来自C或C++代码实现。如果给成员变量加@transient注解的话,则相应的成员变量不会被序列化,此时如果进行反序列化的话,对应成员变量为null。
abstract class A {
//native用于标记 cplusplusMethod为c或c++中实现的本地方法
@native def cplusplusMethod()
}
//标记B可被序列化
//注解声明序列化版本
@SerialVersionUID(1000330L)
@serializable
class B extends A {
//volatile注解标记变量name非线程安全
@volatile var name:String="B"
//transient注解用于标记变量age不被序列化
@transient var age:Int=40
}
@volatile
实际上这个注解或是关键字,大多用于被并发访问的共享变量。在JVM内存模型中happens-before规则有一条就是volatile变量法则(有兴趣可以阅读Java并发编程实践 第16章Java内存模型),对于volatile变量,同一变量的写操作总是先于读操作。
class Person(@volatile var name: String) {
def set(changedName: String) {
name = changedName
}
}
@tailrec
这个注解是与尾递归优化有关的。
// 阶乘
def factorial(n: Int) = {
@tailrec def go(n: Int, acc: Int): Int = {
if (n <=0) acc
else go(n-1, acc * n)
// 尾递归,顾名思义方法的调用也必须出现在返回值的位置
}
go(n, 1)
}
@Unchecked
一般是在模式匹配的时候用到的,告诉编译器有些地方不用"检查"了。如前所述,List[String @ unchecked]。
@transient
这个注解一般用于序列化的时候,标识某个字段不用被序列化。
import java.io.{ FileOutputStream, FileInputStream }
import java.io.{ ObjectOutputStream, ObjectInputStream }
class Hippie(val name: String, @transient val age: Int) extends Serializable
object Serialization {
val fos = new FileOutputStream("hippie.txt")
val oos = new ObjectOutputStream(fos)
val p1 = new Hippie("zml", 34)
oos.writeObject(p1)
oos.close()
}
object Deserialization extends App {
val fis = new FileInputStream("hippie.txt")
val ois = new ObjectInputStream(fis)
val hippy = ois.readObject.asInstanceOf[Hippie]
println(hippy.name)
println(hippy.age)
ois.close()
}
运行之后的结果
zml
0
由于age被标记为@transient,在反序列化的时候,就获取不到原始值了所以被赋值为默认值。
@inline
@inline能够避免方法的参数被放到栈上,以及"显示的调用"。因为编译器在编译的时候会将整个方法复制到它被调用的地方。