相信大多数人都在Java之中听说过反射,我们经常使用它来完成,我们对于目标类内原本无法访问的东西的操作。这里稍微对比一下Java反射,着重介绍Kotlin中的反射。
首先,先要介绍一个概念-----元编程。
- 什么是元编程?
描述数据的数据我们称它为元数据。我们将程序看成描述需求的数据,进而得出描述程序的数据为元数据。而操作元数据的编程就可以称之为元编程。
用一句话来概括就是:程序即是数据,数据即是程序。前半句指的是访问描述程序的数据,如我们通过反射获取类型信息。后半句是指将这些数据转化为对应的程序,即代码生成。
下面介绍一下,常见的元编程技术思路:
- 1.运行时通过API暴露程序信息。我如们常用的反射。
- 2.动态执行代码。如JS中的eval函数。
- 3.通过外部程序实现目的。比如编译器。
上述思路在编程语言中的体现: - 1.反射
- 2.宏
- 3.模板元编程
- 4.路径元编程
- 反射驾到
前面扯了这么久,终于到主角了。我们看看Java反射的基本数据结构。
再看看Kotlin的反射基本数据类型。
- 1.区别
观察上面两个图不难发现:
- Kotlin的KClass和Java的Class可以看做一个含义的类型,并且可以通过.java和.kotlin方法在KClass和Class之间进行转换。
- Kotlin的KCallable和Java的AccessiableObject都可以理解为可调用元素。
- Kotlin的KProperty和Java的Field不太相同。Kotlin的KProperty通常指相应的Getter和Setter整体作为一个KProperty,而Java的Field通常仅仅指字段本身。
- 2.Kotlin的KClass
介绍几个,详细可以用IDEA查看
属性或者函数 |含义 |调用方法
isCompanion |是否伴生对象 | ::class.isCompanion|
isData|是否数据类 | 类似|
isSealed|是否密封类 | 类似|
objectInstance| 是否object实例 |类似 - 3.Kotlin的KCallable
介绍几个:
|isAbstract |是否抽象 | ::class.members.forEach { println(it.name) }|
|isFinal|是否为final | 类似|
|isOpen|是否为open | 类似|
|name| 名称获取 |类似
例子:
类定义,
sealed class Expr{
abstract fun isZero():Boolean
abstract fun isAddZero():Boolean
abstract fun simplifyExpr():Expr
val v = CarClass.vistor
class Num(val value:Int): Expr(){
override fun isAddZero(): Boolean = v.matchAddZero(this)
override fun isZero(): Boolean = v.matchZero(this)
override fun simplifyExpr(): Expr = v.doSimplifyExpr(this)
}
class Operate(val opName:String, val left:Expr, val right:Expr):Expr(){
override fun isAddZero(): Boolean = v.matchZero(this)
override fun isZero(): Boolean = v.matchAddZero(this)
override fun simplifyExpr(): Expr = this
}
}
调用API,
fun main(args:Array<String>) {
Expr::class.members.forEach { println(it.name) }
}
输出结果:
v
isAddZero
isZero
simplifyExpr
equals
hashCode
toString
- 4.获取参数信息
- KParameter
常用:
index| isOptional | isVararg | kind | name | type | returnType
用法:
::class.members.index - KType
常用:
arguments| classifier | isMarkedNullable
用法:
::class.members.returnType.classifier - KTypeParameter
用法:
::class.members.typeParameters