本章要点
本章需要Java、Spring相关的基础
注解让可以在程序的各项条目中添加信息,这些信息可以被编译器或外部工具处理
可以为类、方法、字段、局部变量、参数、表达式、类型参数以及各种类型定义添加注解
表达式和类型的注解跟在被注解的条目之后
注解的形式
生成等效的java修饰符@volatile,@transient,@strictfp,@native
@throws生成与java兼容的throws规格说明
@tailrec校验某个递归函数使用了尾递归优化
assert函数使用了@elidable注解
@deprecated标记已过时的特性
什么是注解
注解是插入代码以便有工具可以对它们进行处理的标签,工具可以在代码级别运作,也可以处理被编译器加入了注解信息的类文件
注解在Java中广泛使用
注解的语法和Java 一样
可以对Scala类使用Java注解,也可以使用Scala独有的注解
Java注解不影响编译器如何将源码翻译成字节码,仅仅是在字节码中添加数据,以便外部工具可以利用他们,在Scala中,注解可以影响编译过程
什么可以被注解
类、方法、字段、局部变量、参数等
可以同时添加多个注解,不区分先后顺序
maven依赖
< ! -- https: / / mvnrepository. com/ artifact/ javax. persistence/ javax. persistence- api -- >
< dependency>
< groupId> javax. persistence< / groupId>
< artifactId> javax. persistence- api< / artifactId>
< version> 2.2 < / version>
< / dependency>
< ! -- https: / / mvnrepository. com/ artifact/ org. testng/ testng -- >
< dependency>
< groupId> org. testng< / groupId>
< artifactId> testng< / artifactId>
< version> 6.14 .3 < / version>
< / dependency>
import javax. persistence. { Entity, Id}
import org. testng. annotations. Test
import scala. beans. BeanProperty
@Entity abstract class Credentials
@Test def testSomeFeature ( ) { }
@BeanProperty
@Id var username = ""
def doSomething ( @NotNull mesage: String) { }
在给主构造器添加注解时,需要将注解放置在构造器之前,并加上一对圆括号(如果注解不带参数的话)
class Credentials1 @Inject ( ) ( var username: String, var passwd: String)
( myMap. get ( key) : @unchecked ) match { }
class MyContainter [ @specialized T]
def country: String @Localized
注解参数
Java注解可以有带名参数
如果参数名为value,则该名称可以省去
如果注解不带参数,则圆括号可以省去
大多数注解参数都有默认值
@Test ( timeout = 100 , expected = classOf[ IOException] )
@Named ( "creds" ) var cred: Credentials = _
@Entity class Credentials
Java注解的参数类型只能是,数值型字面量、字符串、类字面量、Java枚举、其他注解、上述类型的数组
Scala注解的参数可以是任何类型,但是少数注解利用了这个额外的灵活性
注解实现
明白自己的注解类是怎么实现的
注解必须扩展Annotation特质,例如unchecked注解
类型注解必须扩展自TypeAnnotation特质 ,例如Localized注解
Java注解需要使用Java编写
class unchecked extends annotation. Annotation
class Localized extends StaticAnnotation with TypeConstraint
注解的作用是描述那些注解的表达式、变量、字段、方法、类、类型,
Scala的字段定义可能会引出多个Java特性,它们都有可能被添加注解
默认情况下,构造器参数注解仅应用到参数自身,而字段注解只能应用到字段,元注解(@param、@field、@getter、@setter、@beanGetter、@beanSetter)将使注解敷在别处
针对Java特性的注解
Java修饰符
对于不常用的Java特性,scala使用注解而不是修饰符关键字
@vilatile注解将字段标记为易失的,易失的字段可以被多个线程同时更新
@transient注解将字段标记为瞬态的,瞬态的字段不会被序列化,对于临时保存的缓存数据
@strictfp注解对应Java中的strictfp修饰符,使用IEEE的double值进行浮点计算,而不是使用80位扩展精度(Intel处理器的默认实现),使代码移植性更高
@native标记在C或C++中实现的方法,对于Java的native修饰符
标记接口
@cloneable和@remote标记可被克隆的和远程的对象
对于可序列化的类,使用@SerialVersionUID注解指定序列化的版本
受检异常
如果从Java调用Scala的方法,其签名包含那些可能被抛出的受检异常,用@throws生成正确的签名
如果没有@throws注解,java代码将不能捕获该异常
变长参数
@varargs注解使得可以从java调用scala的带有变长参数的方法
def process ( arg: String* ) { }
def process ( arg: Seq[ String] ) { }
@varargs def process1 ( args: String* ) { }
void process1 ( String. . . args)
JavaBeans
@BeanProperty注解,除了scala版的getter和setter还会生成Java版的getter和setter
@BooleanBeanProperty对类型为Boolean的字段生成带有is前缀的getter方法
用于优化的注解
尾递归
递归调用有时能被转化成循环,节约栈空间
sum的最后一步是加法不是递归调用,无法被优化
sum2是递归调用同一个方法,编译器会自动对sum2应用尾递归优化
sum2(1 to 1000000)会报错 栈溢出错误,sum2(1 to 1000000,0)能够正常得到结果
def sum ( xs: Seq[ Int] ) : BigInt= {
if ( xs. isEmpty) 0 else xs. head + sum ( xs. tail)
}
def sum2 ( xs: Seq[ Int] , partial: BigInt) : BigInt= {
if ( xs. isEmpty) partial else sum2 ( xs. tail, xs. head + partial)
}
使用@tailrec注解,如果编译器无法优化,就会报错
例如将sum2放在类中,可以声明为final或private或者放在object中
import scala. annotation. tailrec
class A {
@tailrec def sum2 ( xs: Seq[ Int] , partial: BigInt) : BigInt= {
if ( xs. isEmpty) partial else sum2 ( xs. tail, xs. head + partial)
}
}
报错error: could not optimize @tailrec annotated method sum2: it is neither private nor final so can be overridden
跳转表生成与内联
C++或java中的,switch语句通常可以编译成跳转表,比if/else更高效
scala 也会对匹配语句生成跳转表,@switch注解可以检查match语句是不是被编译成了跳转表
import scala. annotation. switch
var n : Int = 0
( n: @switch ) match{
case 0 = > "Zero"
case 1 = > "one"
case _ = > "?"
}
内联:将方法调用语句替换为被调用的方法体
@inline建议编译器内联,@noinline告诉编译器不要内联
可省略方法
基本类型特殊化
用于错误和警告的注解
@deprecated注解,编译器遇到时会发出警告信息,两个选填参数,message和since
@deprecatedName 可以被应用到参数上,给出一个该参数之前使用过的名称,例如@deprecatedName('sz)
,符号——以单引号开头的名称,符号表示程序中某个项目的名称
@deprecatedInheritance和@deprecatedOverriding针对从某个类继承或重写方法的情况生成过期警告,对应的类或方法在以后的版本可能被改成final
@implicitNotFound,@implicitAmbiguous某个隐式参数不存在或不明确的时候生成有意义的错误提示
@unchecked 匹配不完整时取消警告信息
@uncheckedVariance取消与型变相关的错误提示