1.什么是元编程
元数据:描述数据的数据。
元编程:操作元数据的编程。
程序即是数据:访问描述程序的数据,如通过反射获取类型信息。
数据即是程序:将这些数据转化成对应的程序,也就是所谓代码生成。
总结:
- 元编程是指操作元数据的编程。
- 元编程可以消除某些样板代码。
常见的元编程技术:反射、宏、模板元编程、路径依赖类型。
2.Kotlin与Java反射
- Kotlin 的 KClass 和 Java 的 Class 可以看做同一个含义的类型,并且可以通过 .java 和 .kotlin 方法在 KClass 和 Class 之间互相转化。
- Kotlin 的 KCallable 和 Java 的 AccessiableObject 都可以理解为可调用元素。Java 中构造方法为一个独立的类型,而 Kotlin 则统一作为 KFunction 处理。
- Kotlin 的 KProperty 和 Java 的 Field 不太相同。Kotlin 的 KProperty 通常指相应的 Getter 和 Setter 整体作为一个 KProperty,而 Java 的 Filed 通常仅仅指字段本身。
3.Kotlin的KClass
属性或函数名称 | 含义 |
---|---|
isCompanion | 是否是伴生对象 |
isData | 是否数据类 |
isSealed | 是否密封类 |
objectInstance | object实例 |
companionObjectInstance | 伴生对象实例 |
declaredMemberExtensionFunctions | 扩展函数 |
declaredMemberExtensionProperties | 扩展属性 |
memberExtensionFunctions | 本类及超类扩展函数 |
memberExtensionProperties | 本类及超类扩展属性 |
starProjectedType | 泛型通配类型 |
4.Kotlin的KCallable
Kotlin 把 Class 中的属性(Property)、函数(Function)、甚至构造函数都看作 KCallable,因为他们是可调用的,都是 Class 的成员。
API | 描述 |
---|---|
isAbstract:Boolean<KParameter> | 此 KCallable 是否为抽象的 |
isFinal:Boolean | 此 KCallable 是否为final |
isOpen:Boolean | 此 KCallable 是否为open |
name:String | 此 KCallable 的名称 |
parameters:List<KParameter> | 调用此 KCallable 需要的参数 |
returnType:KType | 此 KCallable 的返回类型 |
typeParameters:List<KTypeParameter> | 此 KCallable 的类型参数 |
visibility:KVisibility? | 此 KCallable 的可见性 |
call(vararg args: Any?): R | 给定参数调用此 KCallable |
5.获取参数信息
函数的参数:KParameter
API | 描述 |
---|---|
index:Int | 返回该参数在参数列表里面的index |
isOptinoal:Boolean | 该参数是否为Optional |
isVararg:Boolean | 该参数是否为Vararg |
kind:Kind | 该参数的kind |
name:String? | 该参数的名称 |
type:KType | 该参数的类型 |
函数的返回值:KType
API | 描述 |
---|---|
arguments:List<KTypeProjection> | 该类型的类型参数 |
classifier:KClassifier? | 该类型在类声明层面的类型(忽略类型参数) |
isMarkedNullable:Boolean | 该类型是否标记为可空类型 |
类型参数:KTypeParameter
6.Kotlin的注解
创建注解:annotation class XXX
和Java一样,注解的参数只能是常量,并且仅支持下列类型:
- 与Java对应的基本类型;
- 字符串;
- Class对象(KClass或者Java的Class);
- 其他注解;
- 上述类型数组。注意基本类型数组需要指定为对应的XXXArray,例如IntArray。
Kotlin与Java 的元注解:
Kotlin | Java | |
---|---|---|
注解用途 | kotlin.annotation.Retention | java.lang.annotation.Retention |
用于何处 | kotlin.annotation.Target | java.lang.annotation.Target |
文档 | kotlin.annotation.Documented | java.lang.annotation.Documented |
可重复 | kotlin.annotation.Repeatable | java.lang.annotation.Repeatable |
Kotlin目前不支持 Inherited 注解。
Retention取值:
取值 | 说明 |
---|---|
SOURCE | 仅在源代码中存在,编译后class文件中不包含该注解信息 |
CLASS | class文件中存在该注解,但不能被发射读取 |
RUNTIME | 注解信息保存在class文件中并且可以在运行时通过反射获取 |
Target取值:
Kotlin | Java | 说明 |
---|---|---|
CLASS | TYPE | 作用于类 |
ANNOTATION_CLASS | ANNOTATION_TYPE | 作用于注解本身(即元注解) |
TYPE_PARAMETER | TYPE_PARAMETER | 作用于类型参数 |
PROPERTY | - | 作用于属性 |
FIELD | FIELD | 作用于字段(属性通常包含字段Getter以及Setter) |
LOCAL_VARIABLE | LOCAL_VARIABLE | 作用于局部变量 |
VALUE_PARAMETER | - | 作用于val参数 |
CONSTRUCTOR | CONSTRUCTOR | 作用于构造函数 |
FUNCTION | METHOD | 作用于函数 |
PROPERTY_GETTER | - | 作用于Getter |
PROPERTY_SETTER | - | 作用于Setter |
TYPE | TYPE_USE | 作用于类型 |
EXPRESSION | - | 作用于表达式 |
FILE | PACKAGE | 作用于文件开头/包声明 |
TYPEALIAS | - | 作用于类型别名 |
构造函数:
注解可以有接受参数的构造函数。允许的参数类型有:
- 对应于 Java 原生类型的类型(Int、 Long等);
- 字符串;
- 类(::class);
- 枚举;
- 其他注解;
- 上面已列类型的数组。
注解使用处目标:
@file,@property,@field,@get,@set,@receiver,@param,@setparam,@delegate
7.获取注解信息
- 通过反射获取注解信息
- 注解处理器