Scala 注解

本文深入探讨Scala中的注解使用,包括注解的种类、作用范围、参数类型、实现方式及优化效果。涵盖Java修饰符注解、尾递归优化、跳跃表生成、内联与可省略方法、基本类型特殊化等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.本章要点

  • 可以为类、方法、字段、局部变量、参数、表达式、类型参数以及各种类型定义添加注解

  • 对于表达式和类型,注解跟在被注解的条目之后

  • 注解的形式有@Annotation、@Annotation(value)或@Annotation(name1=value1,...)

  • @volatile、@transient、@strictfp、@native分别生成等效的Java修饰符

  • 用@tailrec注解让你校验某个递归函数使用了尾递归化

  • assert函数利用了@elidable注解,可以从Scala程序中移除所有断言

  • 用@desprecated注解来标记已过时的特性 

 

2.什么是注解

    注解是插入到代码中以便有工具可以对它们处理的标签。工具可以在代码级别运作,也可以处理被编译器加入注解信息的类文件。可以对Scala使用Java注解或Scala注解。

    注:Java注解并不影响编译器如何将源码翻译成字节码(它们仅仅是往字节码中添加数据,以便外部工具可以利用它们),在Scala中,注解可以影响编译过程(如@BeanProperty会出发getter和setter方法生成)。

 

3.什么可以被注解

    类,方法,字段,局部变量,参数添加注解。

    注:可以同时添加多个注解,先后顺序没影响;

        主构造器添加注解时,注解应该放在构造器之前并加圆括号(注解无参数);

        表达式加注解,需要在表达式后加冒号,然后注解;

        参数类型,实际类型注解。。。  

 

4.注解参数

    Java注解可以有带名参数;参数名为value可以直接略去;大多数注解参数都有缺省值(如Junit的@Test默认timeout参数有默认为0)。

    Java注解的参数类型只能是:

  • 数值型的字面量;

  • 字符串;

  • 类字面量;

  • Java枚举;

  • 其他注解;

  • 上述类型的数组(但不能是数组的数组)

    Scala的注解的参数类型可以是任何类型。。。

 

5.注解实现

  注解必须扩展Annotation特质,例:class unchecked extends annotation.Annotation

      注解类可以选择扩展StaticAnnotation或ClassfileAnnotation特质。StaticAnnotation在编译单元中可见(放置在Scala特有的元数据到类文件中)。而ClassfileAnnotation的本意是在类文件中生成Java注解元数据(Scala2.9不支持该特性)。

 

6.正对Java特性的注解

    Scala提供了一组与Java互操作的注解。

6.1 Java修饰符

    对于那些不是很常用的Java特性,Scala使用注解,而不是修饰符关键字。

@volatile注解将字段标记为易失的(可以被多个线程同时跟新),对应volatile;
@transient将字段标记为瞬态的(不会被序列化,对临时保存的缓存数据或者能够从新计算的数据合理),在JVM转换为transient;
@strictfp使用IEEE使用double值来进行浮点运算(计算更慢,代码移植性高),对应strictfp;
@native标记C或C++方法,对应native

6.2 标记接口

注:@seriliable已经过时,扩展scala.Serializable特质;
于可序列化的类,用@SerialVersionUID指定序列化版本

6.3 受检异常

    和Scala不同,Java编译器会跟踪受检异常。如果从Java代码中调用Scala的方法,其签名应包含那些可能被抛出的受检异常(用@throws注解生成正确的签名)。

6.4 变长参数

def process(arg:String *)   =>
//scala编译器会把变长参数翻译称序列(在Java中费劲)
def process(args:Seq[String])

//加入@varargs会翻译称如下
 process(String... args)

6.5 JavaBeans

@BeanProperty注解生成JavaBean风格的getter和setter方法;

@BooleanProperty生成带有is前缀的getter方法,用于Boolean

7.用于优化的注解

    Scala类库中的有些注解可以控制编译器优化。

7.1 尾递归

    递归调用有时能转换为循环,以节省栈空间。尾递归优化(由于计算过程的最后一步是递归调用同一个方法,因此它可以被变换为跳回到方法顶部的循环)。

object Util{
def sum(xs:Seq[Int]):BigInt={
if(xs.isEmpty) 0 else xs.head+sum(xs.tail)
}
}//栈溢出错误sum(1 to 1000000)


//优化(Scala会自动应用尾递归优化)
def sum2(xs:Seq[Int],partial:BigInt):BigInt={
if (xs.isEmpty) partial else sum2(xs.tail,xs.head+partial)
}

//注:尽管Scala会尝试使用尾递归优化,但有时某些不太明显的原因会造成它无法这么做。如果有赖于编译器消除递归,可以加上@tailrec注解(如果不能呢个优化,则会报错)。

7.2 跳跃表生成与内联

    在Java/C++中,switch语句通常可以被翻译成跳跃表(比if/else更高效)。

    Scala也会尝试对匹配语句生成跳跃表,可以用@switch注解检查Scala语句是不是被编译成了跳跃表,例:

(n:@switch) match{
case 0=>"Zero"
...
}

    内联:将方法调用替换为被调用的方法体,可以使用@inline和@noinline告诉编译器需不需要内联。

7.3 可省略方法

    使用@elidable注解给可以在生产代码中移除的方法打上标记,elidable对象有如下数量值:使用scalac -Xelide-below INFO xx.scala编译(低于1000的方法会被忽略)

7.4 基本类型的特殊化

// 1.打包和解包基本类型的值是不高效的——在泛型代码中很常见。例:
def allDifferent[T](x:T,y:T,z:T)=x!=y&&x!=z&&y!=z
//调用之前每个值会包装成一个java.lang.Integer
allDifferent(1,2,3)
//也可以重载限定类型
 


// 2.可以使用@specialized注解限定可选类型子集,例:
//自动生成各种类型的方法
def allDifferent[@specialized T](x:T,y:T,z:T)....
//限定子集
def allDifferent[@specialized(Long,Double) T]().....

8.用于错误和警告的注解

  • 如果给某个特性加上@deprecated注解,每当编译器遇到对这个特性使用时都会生成一个警告信息(有两个参数message和since);

  • @deprecatedName可以被应用到参数上(单引号开头,检查名称是否过时,这是符号,效率比字符串高);

  • @implicitNotFound注解用于某个隐式参数不存在时生成有意义的错误提示;

  • @unchecked注解用于匹配不完整信息时取消警告信息;

  • @uncheckedvariance注解会取消与型变相关的错误提示;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员学习圈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值