美文网首页
Kotlin编码窍门之注解(Annotations)

Kotlin编码窍门之注解(Annotations)

作者: 已迁至知乎_此不再维护 | 来源:发表于2017-06-12 17:37 被阅读0次

注解声明(Annotation Declaration)

注解是将元数据附加到代码的手段。 要声明注解,请将annotation修饰符放在类的前面:

annotation class Fancy

注解的附加属性可以通过使用元注解类来指定:

  1. @Target指定可以用该注解标注的元素的可能的类型(类、函数、属性、表达式等)
  2. @Retention指定该注解是否存储在编译后的class文件中,以及它在运行时是否通过反射可见(默认都是true)
  3. @Repeatable注解允许在单个元素上多次使用相同的该注解
  4. @MustBeDocumented表明该注解是公有API的一部分,并且应该包含在生成的API文档中显示的类或方法的签名中

如下:

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION,
        AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
@MustBeDocumented
annotation class Fancy

用法

@Fancy class Foo {
    @Fancy fun baz(@Fancy foo: Int): Int {
        return (@Fancy 1)
    }
}

如果你需要注解一个类的私有构造器,你需要在构造器声明处添加constructor关键字,并在该关键字之前添加注解:

class Foo @Inject constructor(dependency: MyDependency) {
    // ...
}

你也可以对属性访问器进行标注:

class Foo {
    var x: MyDependency? = null
        @Inject set
}

构造器

注解也可以有接受参数的构造器:

annotation class Special(val why: String)

@Special("example") class Foo {}

合法的参数类型有:

  1. 原生类型
  2. 字符串
  3. 枚举
  4. 其他注解
  5. 上述类型的数组

注解类型不能有可null类型,因为JVM不支持将null作为注解属性的值存储。

如果注解用作另一个注解的参数,则其名称不以@字符为前缀:

annotation class ReplaceWith(val expression: String)

annotation class Deprecated(
        val message: String,
        val replaceWith: ReplaceWith = ReplaceWith(""))

@Deprecated("This function is deprecated, use === instead", ReplaceWith("this === other"))

如果需要将一个类指定为注解的参数,请使用Kotlin类。Kotlin编译器会自动将其转换为Java类,以便Java代码能够正常看到该注解和参数。

import kotlin.reflect.KClass

annotation class Ann(val arg1: KClass<*>, val arg2: KClass<out Any?>)

@Ann(String::class, Int::class) class MyClass

λ表达式

注解也可以用于λ表达式。它们将被应用于λ表达式方法体生成的invoke()方法。这对于像Quasar这样的框架很有用,该框架使用注解进行并发控制:

annotation class Suspendable

val f = @Suspendable { Fiber.sleep(10) }

明确注解目标(Annotation Use-site Targets)

当对一个属性或一个主构造器的参数进行注解时,Kotlin元素将会生成对应的多个Java元素,因此在Java字节码中该注解有多个可能位置。如果要精确指定该如何生成该注解,请使用以下语法:

class Example(@field:Ann val foo,    // annotate Java field
              @get:Ann val bar,      // annotate Java getter
              @param:Ann val quux)   // annotate Java constructor parameter

可以使用相同的语法来标注整个文件。要做到这一点,把带有目标file的注解放在文件的顶层:package指令之前或在所有导入之前(如果文件在默认包中的话):

如果对同一目标有多个注解,可以使用下述方法来避免目标重复:在目标后面添加方括号并将所有注解放在方括号内:

class Example {
     @set:[Inject VisibleForTesting]
     var collaborator: Collaborator
}

支持使用明确注解目标的完整列表是:

  1. file
  2. property (annotations with this target are not visible to Java)
  3. field
  4. get (property getter)
  5. set (property setter)
  6. receiver (receiver parameter of an extension function or property)
  7. param (constructor parameter)
  8. setparam (property setter parameter)
  9. delegate (the field storing the delegate instance for a delegated property)

要标注扩展函数的接收者参数,请使用以下语法:

fun @receiver:Fancy String.myExtension() { }

如果你没有指明目标使用处,通过正在使用的@Target注解来选择目标。如果有多个适用的目标,则使用以下列表中第一个可用的:

  1. param
  2. property
  3. field

Java注解

Java注解与Kotlin完全兼容:

import org.junit.Test
import org.junit.Assert.*
import org.junit.Rule
import org.junit.rules.*

class Tests {
    // apply @Rule annotation to property getter
    @get:Rule val tempFolder = TemporaryFolder()

    @Test fun simple() {
        val f = tempFolder.newFile()
        assertEquals(42, getTheAnswer())
    }
}

由于Java编写的注解没有定义参数的顺序,所以不能使用常规函数调用语法来传递参数。相反,你需要使用明明才函数语法:

// Java
public @interface Ann {
    int intValue();
    String stringValue();
}
// Kotlin
@Ann(intValue = 1, stringValue = "abc") class C

和Java一样,特殊情况是value参数;它的值无需显式名称指定。

// Java
public @interface AnnWithValue {
    String value();
}
// Kotlin
@AnnWithValue("abc") class C

如果在Java中value参数的类型是数组,则它在Kotlin中将是vararg参数:

// Java
public @interface AnnWithArrayValue {
    String[] value();
}
// Kotlin
@AnnWithArrayValue("abc", "foo", "bar") class C

对于具有数组类型的其他参数,需要显式使用arrayOf

// Java
public @interface AnnWithArrayMethod {
    String[] names();
}
// Kotlin
@AnnWithArrayMethod(names = arrayOf("abc", "foo", "bar")) class C

注解实例的值会作为使用暴露给Kotlin代码:

// Java
public @interface Ann {
    int value();
}
// Kotlin
fun foo(ann: Ann) {
    val i = ann.value
}

相关文章

网友评论

      本文标题:Kotlin编码窍门之注解(Annotations)

      本文链接:https://www.haomeiwen.com/subject/smalqxtx.html