Kotlin-注解

注解声明

注解是将元数据附加到代码的手段,要声明一个注解,只要把annnotation关键字放在class前面进行修饰即可.

annotation class Fancy

注解的附加属性可以通过注解类和元注解来指定:
- @Target 指定可以用注解进行注解的元素类型
- @Retention 指定注解是否存储在编译后的类文件中,以及是否在运行时通过反射可见(默认情况下,这两个都是真的)
- @Repeatable 允许在同一个元素上多次使用相同的注解
- @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 {}

它的参数类型可以有:
- 类型可以是Java中对应的主要类型(Int,Long等)
- 字符串
- 类 (Foo::class)
- 枚举
- 其他注解
- 前面描述的类型数组

注解的参数一定是非空类型,因为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类(KClass),Kotlin会自动把它转为Java类,所以,java代码就能看到注解和参数正常

import kotlin.reflect.KClass

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

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

Lambds

注解也可以应用在lambdas上面,当lambdas主体代码生成的时候,注解就会应用在invoke方法中,这对于并发控制的框架(Quasar)是非常有用的

annotation class Suspendable

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

注解目标使用场景

当需要把注解应用在属性或主要构造方法的参数时,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

==@field,@get,@param都是Java中的注解==

相同的语法也可以应用在整个文件上,为了达到这个目的,你还需要在文件结构最顶层加上目标文件注解file,在包名和所有import语句之前:

@file JvmName("Foo")
package com.mk;

如果在一个目标中有多个注解,为了避免重复添加目标,可以在目标后面添加括号,把所有注解都放在括号里面:

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

所有可使用的注解列表如下:
- file
- property (这个注解对java不可见)
- field
- get (属性的getter)
- set (属性的setter)
- receiver (拓展函数或属性的接收器参数)
- param (构造方法的参数)
- setparam (属性的setter参数)
- delegate (存储在委托属性的委托实例中的属性)

如果要注解拓展函数的接收器参数,可以用下面的语法:

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

如果你没指定使用目标,那么就可以使用@Target注解来指定,如果有多个可用目标,那么目标列表中的第一个将被使用:
- param
- property
- field

Java中的注解

Java中的注解在Kotlin中也可以编译通过:

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

class Tests {
    // 应用 @Rule 注解在属性的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
}

你可能感兴趣的:(我和Android,Kotlin)