> Chapter10這節還是挺重要的,在看Spark源碼的過程中,發現其源碼使用到很多注解的知識,所以這節一定要好好學習。
### 1. 什么是注解
-
**注解:**是那些你插入到代碼中以方便工具可以對它們進行處理的**標簽**。
-
**注解作用:**是描述那些被注解的表達式、變量、字段、方法或類型。
-
Java中注解不會影響編譯器生成字節碼,而Scala中會影響。
-
下面是注解的一個簡單實例:
~~~
import scala.reflect.BeanProperty
import javax.persistence.Entity
import javax.persistence.Id
import org.junit._
import org.junit.Assert._
@Entity class Credentials {
@Id @BeanProperty var username : String = _
@BeanProperty var password : String = _
}
class MyTest {
@Test(timeout = 100) def testSomeFeature() {
assertTrue(6 * 7 == 42)
}
}
~~~
`@Entity`注解標識該類是一個實體,`@id`是設置主鍵,`@BeanProperty`在Chapter05中講過,它會生成getter和setter兩種方法,`@Test`表示測試方法,在這里可以測試期望異常和超時時間。具體含義可以上google查詢Junit和JPA注解。
### 2. 什么可以被注解
-
類、方法、字段、局部變量和參數都可添加注解。
-
可以添加多個注解,沒有先后順序。
~~~
@BeanProperty @Id var lastName = ""
~~~
-
給主構造函數添加注解時,注解放置在構造器之前,并加上一對圓括號。
~~~
class Credentials @Inject() (var username: String, var password: String) {
}
~~~
-
給表達式添加注解,需要在表達式后添加冒號,然后是注解。
~~~
(n: @unchecked) match { ... }
~~~
### 3. 注解參數
-
注解可以帶參數。
~~~
@Test(timeout = 100, expected = classOf[IOException])
def testNonexistentFile() {
new FileReader("/fred.txt")
}
~~~
-
注解不帶參數,圓括號可以省略。注解有默認值,比如Test的Timeout的默認值為0,表示沒有超時,expected默認是不預期任何異常。
### 4. 針對Java特性的注解
-
`@volatile`將字段標記為易失的,易失的字段可以被多個線程同時更新。
-
`@transient`將字段標記為瞬態的,瞬態的字段不會被序列化,只會作為臨時的緩存數據。(序列化:將對象狀態信息轉換為可以存儲或傳輸的形式的過程)
-
`@strictfp`使用IEEE的double進行浮點計算,而不是使用80位擴展精度,計算慢但移植性高。
-
`@native`標記在C或C++代碼中的實現方法。
### 5. 標記接口
-
`@cloneable`和`@remote`標記接口可被克隆或遠程的對象。
-
`@SerialVersionUID`指定序列化版本,標記可序列化的類。
~~~
@cloneable @remote @SerialVersionUID(6157032470129070425L)
class Employee(var name: String, var salary: Double) extends Serializable {
var hireDay = new Date
}
~~~
### 6. 受檢異常和變長參數
-
`@throws`標記可能拋出異常的對象。
-
`@varargs`可以讓你從Java調用Scala的帶有變長參數的方法。
~~~
class Processor {
@varargs def process(args: String*) {
println(args.mkString("<", "|", ">"))
}
}
~~~
### 7. 跳轉表生成與內聯
- C++和Java中switch通常被編譯為跳轉表,更高效,`@switch`檢查Scala是不是將match編譯成跳轉表。
~~~
(n: @switch) match {
case 0 => "Zero"
case 1 => "One"
case _ => "?"
}
~~~
- `@inline`將方法標記為內聯方法,`@noinline`告訴編譯器不要內聯。
### 8. 可省略方法
-
`@elidable`給生產代碼中需要移除的方法打上標記。它后面會接一個參數,
~~~
@elidable(800) def dump(props: Map[String, String]) {}
~~~
-
編譯時需要使用下面命令:
~~~
scalac -Xelide-below 800 prog.scala
~~~
-
具體參數表如下,默認值低于1000的方法都會被省略。

### 9. 基本類型的特殊化
-
給類型參數添加`@specialized`注解,**編譯器會自動生成對應類型的所有方法**。不需要自己寫重載函數。
-
可用的類型有:**Unit、Boolean、Byte、Short、Char、Int、Long、Float、Double**。
~~~
def allDifferent[@specialized(Double, Long) T](x: T, y: T, z: T) = x != y && x != z && y != z
~~~
### 10. 用于錯誤和警告的注解
-
`@deprecated`注解被添加后,編譯器遇到被注解的方法使用時就會生成一個警告,它有兩個參數可選,messsage和since。
~~~
@deprecated(message = "Use factorial(n: BigInt) instead")
def factorial(n: Int): Int = if (n <= 0) 1 else n * factorial(n - 1)
~~~
-
`@implicitNotFound`注解用于某個隱式參數不存在時會生成有意義的錯誤提示。
-
`@unchecked`注解用于在匹配不完整時取消警告信息。
【待續】