Initial commit

This commit is contained in:
2025-06-25 19:05:35 +08:00
commit e949662e7c
104 changed files with 11697 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
# 关于此文档
> 此文档由 [VuePress](https://v2.vuepress.vuejs.org/zh) 强力驱动。
## 许可证
[Apache-2.0](https://github.com/HighCapable/KavaRef/blob/main/LICENSE)
```:no-line-numbers
Apache License Version 2.0
Copyright (C) 2019 HighCapable
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```
版权所有 © 2019 HighCapable

View File

@@ -0,0 +1,21 @@
# 更新日志
> 这里记录了 `KavaRef` 的版本更新历史。
::: danger
我们只会对最新的 API 版本进行维护,若你正在使用过时的 API 版本则代表你自愿放弃一切维护的可能性。
:::
## kavaref-core
### 1.0.0 | 2025.06.25 &ensp;<Badge type="tip" text="最新" vertical="middle" />
- 首个版本提交至 Maven
## kavaref-extension
### 1.0.0 | 2025.06.25 &ensp;<Badge type="tip" text="最新" vertical="middle" />
- 首个版本提交至 Maven

View File

@@ -0,0 +1,15 @@
# 联系我们
> 如在使用中有任何问题,或有任何建设性的建议,都可以联系我们。
加入我们的开发者群组。
- [点击加入 Telegram 群组](https://t.me/KavaRef)
- [点击加入 Telegram 群组 (开发者)](https://t.me/HighCapable_Dev)
- [点击加入 QQ 群 (开发者)](https://qm.qq.com/cgi-bin/qm/qr?k=Pnsc5RY6N2mBKFjOLPiYldbAbprAU3V7&jump_from=webapi&authKey=X5EsOVzLXt1dRunge8ryTxDRrh9/IiW1Pua75eDLh9RE3KXE+bwXIYF5cWri/9lf)
**酷安** 找到我 [@星夜不荟](http://www.coolapk.com/u/876977)。
## 助力维护
感谢您选择并使用 `KavaRef`,如有代码相关的建议和请求,可在 GitHub 提交 Pull Request。

View File

@@ -0,0 +1,113 @@
# 展望未来
> 未来是美好的,也是不确定的,让我们共同期待 `KavaRef` 在未来的发展空间。
## 未来的计划
> 这里收录了 `KavaRef` 可能会在后期添加的功能。
### 支持通过 ClassLoader 过滤 Class
`KavaRef` 目前仅支持 `Method``Field``Constructor` 等反射 API 的查找和调用,
未来可能会根据需求在 Java 与 Android 平台支持通过指定类型的 `ClassLoader` 过滤 `Class` 的功能。
目前,你可以使用 [DexKit](https://github.com/LuckyPray/DexKit) 来完成这一需求,它同时支持更加复杂的 Method、Field、Constructor 等反射 API 的查找和调用。
### 自动生成反射代码
**这是在 [YukiReflection](https://github.com/HighCapable/YukiReflection) 中已经初步立项的功能,`KavaRef` 准备在未来可能的时间里继续实现它。**
使用 `stub` 的方式创建一个 Kotlin 类,并声明其中的参数,以及其在各个版本中的不同状态。
比如下面的这个 Java 类就是我们需要反射的目标类。
> 示例如下
```java:no-line-numbers
package com.example.test;
public class MyClass {
private String myField = "test";
public MyClass() {
// ...
}
private String myMethod1(String var1, int var2) {
// ...
}
private void myMethod2() {
// ...
}
private void myMethod3(String var1) {
// ...
}
}
```
通过目前 API 的现有用法可以使用如下方式反射调用这个类。
> 示例如下
```kotlin
MyClass().resolve().apply {
// 调用 myField
val value = firstField { name = "myField" }.get<String>()
// 调用 myMethod1
val methodValue = firstMethod { name = "myMethod1" }.invoke<String>("test", 0)
// 调用 myMethod2
firstMethod { name = "myMethod2" }.invoke()
// 调用 myMethod3
firstMethod { name = "myMethod3" }.invoke("test")
}
```
目前要实现的功能是可以使用反射功能直接定义为如下 Kotlin 类。
> 示例如下
```kotlin
package com.example.test
@ReflectClass
class MyClass {
@ReflectField
val myField: String = fieldValueOf("none")
@ReflectMethod
fun myMethod1(var1: String, var2: Int): String = methodReturnValueOf("none")
@ReflectMethod
fun myMethod2() = MethodReturnType.Unit
@ReflectMethod
fun myMethod3(var1: String) = MethodReturnType.Unit
}
```
然后我们就可以直接调用这个定义好的 Kotlin 类来实现反射功能API 会根据注解自动生成反射代码。
> 示例如下
```kotlin
MyClass().also {
// 调用 myField
val value = it.myField
// 调用 myMethod1
val methodValue = it.myMethod1("test", 0)
// 调用 myMethod2
it.myMethod2()
// 调用 myMethod3
it.myMethod3("test")
}
```
::: tip
以上功能可能会在实际推出后有所变化,最终以实际版本的功能为准。
:::

View File

@@ -0,0 +1,243 @@
# 迁移至 KavaRef
如果你已经习惯使用 [YukiReflection](https://github.com/HighCapable/YukiReflection) 或 [YukiHookAPI](https://github.com/HighCapable/YukiHookAPI) 中的反射 API你可以参考以下内容来迁移至 `KavaRef`
::: warning
针对 `YukiHookAPI`,你需要继续使用其 Hook API`KavaRef` 仅包含 Java 反射相关 API。
:::
## 基本功能
`KavaRef` 的设计理念与 `YukiReflection` 类似,但不完全相同,以下内容列举了 `YukiReflection``KavaRef` 在基本反射功能上的差异,你可以根据这些差异手动进行迁移。
例如我们有以下 Java 类。
> 示例如下
```java :no-line-numbers
public class MyClass {
private static String content = "Hello, World!";
private void myMethod(String content) {
System.out.println("Hello " + content + "!");
}
}
```
以下是 `KavaRef` 与 `YukiReflection` 的使用示例对比。
> 示例如下
<div style="display: flex; gap: 16px;">
<div style="flex: 1;">
<h4>KavaRef</h4>
```kotlin
// 假设这就是你的 MyClass 实例
val myClass: MyClass
// 使用 KavaRef 调用并执行
MyClass::class.resolve().firstMethod {
name = "myMethod"
parameters(String::class)
}.of(myClass).invoke("Hello, KavaRef!")
// 直接引用实例方式
myClass.resolve().firstMethod {
name = "myMethod"
parameters(String::class)
}.invoke("Hello, KavaRef!")
```
</div>
<div style="flex: 1;">
<h4>YukiReflection</h4>
```kotlin
// 假设这就是你的 MyClass 实例
val myClass: MyClass
// 使用 YukiReflection 调用并执行
MyClass::class.java.method {
name = "myMethod"
param(StringClass)
}.get(myClass).call("Hello, YukiReflection!")
// 直接引用实例方式
myClass.current().method {
name = "myMethod"
param(StringClass)
}.call("Hello, YukiReflection!")
```
</div>
</div>
`KavaRef` 在任何时候开始反射都需要使用 `resolve()` 来创建反射作用域,不再对 `Class` 等实例直接进行扩展相关 `method`、`constructor` 方法以避免污染其作用域。
`KavaRef` 抛弃了 "Finder" 的设计理念,使用 "Filter" (过滤器) 的设计理念来获取反射结果,“查找” 不再是查找,而是 “过滤”。
`KavaRef` 取消了 `YukiReflection` 在结果实例中定义获取的 `Member` 为多重还是单一的设计方案,直接返回整个 `List<MemberResolver>`
你在上方看到的示例使用了 `firstMethod` 来获取第一个匹配的 `MethodResolver`,如果你需要获取所有匹配的结果,可以改为 `method`。
`KavaRef` 在 `MethodCondition` 中的条件方法名称已由 `YukiReflection` 之前的 `param` 等简写修改为 `parameters`,以更符合 Java 反射 API 的命名习惯。
`KavaRef` 不再提供条件中的 `param(...).order()` 功能,因为这个功能本身就不稳定,`KavaRef` 现在使用迭代器进行过滤操作,字节码将不再有顺序,且本不应该使用顺序筛选字节码,你可以使用 `firstMethod`、`firstField` 或 `lastMethod`、`lastField` 等方法来获取第一个或最后一个匹配的结果。
`KavaRef` 将 `get(instance)` 方法更名为 `of(instance)`,因为 `get(...)` 可能会与 `Field` 的 `get(...)` 用法产生混淆且语义不明确,
同时 `get(instance)` 也不再是从类似 `MethodFinder.Result` 来获取 `MethodFinder.Result.Instance` 实例,而是使用 `of(instance)` 来始终操作和设置实例对象到 `MemberResolver`。
类似 `MethodFinder.Result.Instance` 中的 `string()`、`int()` 等方法在 `KavaRef` 中已被移除,
你可以直接使用 `get<String>()`、`get<Int>()`、`invoke<String>(...)`、`invoke<Int>(...)` 等方式来获取或调用对应类型的结果。
::: danger
如果你正在查找 (过滤) `Field`,你需要注意 `KavaRef` 与 `YukiReflection` 在 `Field` 的获取方式上有可能会发生语义冲突,在迁移这部分的时候请特别注意。
例如获取 `MyClass` 中的 `content` 静态字段,在 `YukiReflection` 中,你会这样做。
> 示例如下
```kotlin
MyClass::class.java
.field { name = "content" } // 返回 FieldFinder.Result
.get() // 不可省略,返回 FieldFinder.Result.Instance
.string() // 值
```
在 `KavaRef` 中,你需要这样做。
> 示例如下
```kotlin
MyClass::class.resolve()
.firstField { name = "content" } // 返回 FieldResolver<MyClass>
.get<String>() // 值
```
正如上面所说,`get(...)` 在 `YukiReflection` 中是获取 `FieldFinder.Result.Instance` 对象,而不是值,要获取值并处理为指定类型,你需要调用 `string()` 或者 `cast<String>()`,而在 `KavaRef` 中是在 `MemberResolver` 中直接使用 `get<T>()` 来获取指定类型的值,`KavaRef` 对应 `YukiReflection` 的 `get(...)` 的用法是 `of(...)`。
所以上述示例在 `KavaRef` 中的完整写法应该为。
> 示例如下
```kotlin
// 由于调用的是静态实例,"of(null)" 可被省略
MyClass::class.resolve()
.firstField { name = "content" } // 已是调用链对象 FieldResolver<MyClass>
.of(null) // 可省略,返回调用链对象 FieldResolver<MyClass>
.get<String>() // 值
```
:::
`KavaRef` 不再对 `Method` 提供 `call` 方法,现在统一合并为 `invoke` (带泛型参数),同时 `KavaRef` 将 `Constructor` 的 `newInstance` 方法定义为 `create` (带泛型参数)。
你可能注意到条件 `superClass()` 消失了,它还在,在 `KavaRef` 中它已更名为 `superclass()`,对接标准的 Java 反射 API。
同时,`KavaRef` 对 `KClass` 进行了扩展,你不再需要在大部分场景中使用 `Some::class.java` 的方式来声明一个 `Class` 实例。
`KavaRef` 的另一个设计思想就是类型安全,只要是你在使用声明指定泛型类型的 `KClass<T>`、`Class<T>` 时,在 `of(instance)`、`create(...)` 时都会校验、转换为对应类型,在编码期间就完成类型检查,避免运行时错误。
> 示例如下
```kotlin
// 假设这就是你的 MyClass 实例
val myClass: MyClass
// 使用 KavaRef 调用并执行
MyClass::class
.resolve()
.firstMethod {
name = "myMethod"
parameters(String::class)
}
// 只能传入 MyClass 类型的实例
.of(myClass)
.invoke("Hello, KavaRef!")
```
## 其它功能
`KavaRef` 与 `YukiReflection` 在其它功能及扩展功能中的实现差异不大,`KavaRef` 将这些功能单独分离为了一个独立的模块。
以下功能在 `YukiReflection` 中提供,但在 `KavaRef` 中没有实现且不再提供:
- 预置反射类型常量类,如 `StringClass`、`IntType` 等
- 你可以直接使用 `String::class`、`Int::class` 等 Kotlin 的类引用进行替代,对于原始类型与包装类,`IntType` 等价于 `Int::class``IntClass` 等价于 `JInteger::class`
- `DexClassFinder` 功能
- 由于其设计缺陷,且在 Android 平台上使用时可能存在性能问题,目前不再提供
- `RemedyPlan` 和 `method { ... } .remedys { ... }` 功能
- 由于此功能存在可能的黑盒问题,维护相对困难,如需使用类似功能,请手动实现,不再提供
- `ClassLoader.listOfClasses()` 功能
- 由于各个平台实现方案复杂且不稳定,不再提供
- `ClassLoader.searchClass()` 功能
- 由于性能问题,且设计时仅限于 Android 平台使用,过滤条件维护相对困难,不再提供
- `Class.hasExtends`、`Class.extends`、`Class.implements` 功能
- 你可以使用 `A::class isSubclassOf B::class` 来取代它们
- `Class.toJavaPrimitiveType()` 功能
- 功能设计上存在概念混淆问题,不再提供
- `"com.some.clazz".hasClass(loader)` 功能
- 你可以使用 `loader.hasClass("com.some.clazz")` 来取代它
- `Class.hasField`、`Class.hasMethod`、`Class.hasConstructor` 功能
- 由于设计缺陷,不再提供
- `Class.hasModifiers(...)`、`Member.hasModifiers(...)` 功能
- 你可以直接使用 `Class.isPublic`、`Member.isPublic` 等扩展方法来取代它们。
- `Class.generic()`、`GenericClass` 功能
- 如果只是希望获取超类的泛型参数,你可以使用 `Class.genericSuperclassTypeArguments()`,由于设计缺陷,不再提供
- `Class.current()`、`CurrentClass` 功能
- 已合并到 `KavaRef.resolve()` 的核心功能中,不再单独提供
- `Class.buildOf(...)` 功能
- 你可以使用 `Class.createInstance(...)` 来取代它
- `Class.allMethods()`、`Class.allFields()`、`Class.allConstructors()` 功能
- 由于其污染作用域,不再提供
- `YLog` 日志功能
- `KavaRef` 不再接管日志,你可以使用对应平台的实现方式,不再提供
## 异常处理
`KavaRef` 在异常处理方面与 `YukiReflection` 完全不同,`KavaRef` 的异常逻辑将保持默认透明,<u>**它不再主动拦截异常并打印错误日志甚至是提供 `onNoSuchMethod` 监听**</u>,当没有过滤到任何有效的成员时,`KavaRef` 会直接抛出异常,除非你**明确声明条件为可选 (与 `YukiReflection` 逻辑保持一致)**。
> 示例如下
```kotlin
// 假设这就是你的 MyClass 实例
val myClass: MyClass
// 使用 KavaRef 调用并执行
MyClass::class
.resolve()
.optional() // 声明为可选,不要抛出异常
// 使用 firstMethodOrNull 替代 firstMethod因为找不到会抛出 Kotlin 自身的 NoSuchElementException
.firstMethodOrNull {
name = "doNonExistentMethod" // 假设这个方法不存在
parameters(String::class)
}?.of(myClass)?.invoke("Hello, KavaRef!")
```
更多内容请参考 [kavaref-core](../library/kavaref-core.md) 中的 [异常处理](../library/kavaref-core.md#异常处理) 部分。
## 初次使用 KavaRef
如果你没用过 `YukiReflection` 或者 `YukiHookAPI`,没关系,你可以参考以下内容来快速上手。
::: tip 接下来做什么
更多内容,请继续阅读 [kavaref-core](../library/kavaref-core.md) 和 [kavaref-extension](../library/kavaref-extension.md)。
立即开始使用 `KavaRef` 吧!
:::

View File

@@ -0,0 +1,38 @@
# 第三方 Member 解析器
> 这里收录了一些第三方的 Member 解析器,可供参考与使用。
>
> 使用方法请阅读 [自定义解析器](../library/kavaref-core.md#自定义解析器)。
## AndroidHiddenApiBypass
[项目地址](https://github.com/LSPosed/AndroidHiddenApiBypass)
> LSPass: Bypass restrictions on non-SDK interfaces
```kotlin
class AndroidHiddenApiBypassResolver : MemberProcessor.Resolver() {
override fun <T : Any> getDeclaredConstructors(declaringClass: Class<T>): List<Constructor<T>> {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
return super.getDeclaredConstructors(declaringClass)
}
val constructors = HiddenApiBypass.getDeclaredMethods(declaringClass)
.filterIsInstance<Constructor<T>>()
.toList()
return constructors
}
override fun <T : Any> getDeclaredMethods(declaringClass: Class<T>): List<Method> {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
return super.getDeclaredMethods(declaringClass)
}
val methods = HiddenApiBypass.getDeclaredMethods(declaringClass)
.filterIsInstance<Method>()
.toList()
return methods
}
}
```

View File

@@ -0,0 +1,5 @@
# R8 与 Proguard 混淆
> 大部分场景下 Android 应用程序安装包可通过混淆压缩体积,这里介绍了混淆规则的配置方法。
`KavaRef` 在 Android 项目中不需要额外配置任何混淆规则。

View File

@@ -0,0 +1,36 @@
# 介绍
> `KavaRef` 是一个使用 Kotlin 实现的现代化 Java 反射 API。
## 背景
这是一个使用 Kotlin 实现的现代化 Java 反射 API旨在提供更简洁、更易用的 API同时保留 Java 反射的强大功能。
项目图标由 [MaiTungTM](https://github.com/Lagrio) 设计,名称取自 **K**otlinJ**avaRef**lection意为使用 Kotlin 实现的 Java 反射。
它最早诞生于 [YukiHookAPI](https://github.com/HighCapable/YukiHookAPI),后期被解耦合为 [YukiReflection](https://github.com/HighCapable/YukiReflection) 项目。
如你所见,现在 `KavaRef` 是借助 `YukiReflection` 的设计思想完全重构的一套全新 API它们没有从属关系并将取代 `YukiReflection` 成为一个全新的反射解决方案。
如果你正在使用 `YukiReflection` 或与之相关的 `YukiHookAPI` 项目,你可以参考 [这里](../config/migration) 来迁移反射 API 的写法到 `KavaRef`
## 用途
`KavaRef` 采用 Kotlin **lambda** 语法与 Java Builder 风格构建。
它能取代 [Java 原生的反射 API](https://pdai.tech/md/java/basic/java-basic-x-reflection.html),使用更加人性化的语言实现一套更加完善的反射方案。
## 技能要求
你必须已熟练掌握 Java 原生的反射 API了解 Java 的类加载机制、字节码结构以及它们在 Kotlin 中的用法 (如果你正在使用 Kotlin)。
## 语言要求
推荐使用 KotlinAPI 代码构成同样支持 Java但是在纯 Java 项目中 `KavaRef` 有可能无法发挥其全部功能和语法糖优势。
文档全部的 Demo 示例代码都将首先使用 Kotlin 进行描述,如果你完全不会使用 Kotlin 那你将有可能无法更全面地体验和使用 `KavaRef` 的功能。
## 功能贡献
本项目的维护离不开各位开发者的支持和贡献,目前这个项目处于初期阶段,可能依然存在一些问题或者缺少你需要的功能,
如果可能,欢迎提交 PR 为此项目贡献你认为需要的功能或前往 [GitHub Issues](repo://issues) 向我们提出建议。

View File

@@ -0,0 +1,95 @@
# 快速开始
> 集成 `KavaRef` 到你的项目中。
## 项目要求
项目需要使用 `IntelliJ IDEA``Android Studio` 创建且类型为 Java 或 Android 项目并已集成 Kotlin 环境依赖。
- IntelliJ IDEA (建议 [从这里](https://www.jetbrains.com/idea) 获取最新版本)
- Android Studio (建议 [从这里](https://developer.android.com/studio) 获取最新版本)
- Kotlin 1.9.0+、Gradle 8+、Java 17+
### 配置存储库
`KavaRef` 的依赖发布在 **Maven Central** 和我们的公共存储库中,你可以使用如下方式配置存储库。
我们推荐使用 Kotlin DSL 作为 Gradle 构建脚本语言并推荐使用 [SweetDependency](https://github.com/HighCapable/SweetDependency) 来管理依赖。
#### SweetDependency (推荐)
在你的项目 `SweetDependency` 配置文件中配置存储库。
```yaml
repositories:
google:
maven-central:
# (可选) 你可以添加此 URL 以使用我们的公共存储库
# 当 Sonatype-OSS 发生故障无法发布依赖时,此存储库作为备选进行添加
# 详情请前往https://github.com/HighCapable/maven-repository
highcapable-maven-releases:
# 中国大陆用户请将下方的 "raw.githubusercontent.com" 修改为 "raw.gitmirror.com"
url: https://raw.githubusercontent.com/HighCapable/maven-repository/main/repository/releases
```
#### 传统方式
在你的项目 `build.gradle.kts` 中配置存储库。
```kotlin
repositories {
google()
mavenCentral()
// (可选) 你可以添加此 URL 以使用我们的公共存储库
// 当 Sonatype-OSS 发生故障无法发布依赖时,此存储库作为备选进行添加
// 详情请前往https://github.com/HighCapable/maven-repository
// 中国大陆用户请将下方的 "raw.githubusercontent.com" 修改为 "raw.gitmirror.com"
maven("https://raw.githubusercontent.com/HighCapable/maven-repository/main/repository/releases")
}
```
### 配置 Java 版本
在你的项目 `build.gradle.kts` 中修改 Kotlin 的 Java 版本为 17 及以上。
> Java 项目
```kt
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlin {
jvmToolchain(17)
}
```
> Android 项目
```kt
android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
}
```
## 功能一览
整个项目分为多个模块,你可以选择你希望引入的模块作为依赖应用到你的项目中,但一定要包含 **kavaref-core** 模块。
你可以点击下方对应的模块前往查看详细的功能介绍。
- [kavaref-core](../library/kavaref-core.md)
- [kavaref-extension](../library/kavaref-extension.md)
## Demo
你可以在 [这里](repo://tree/main/samples) 找到一些示例,查看对应的演示项目来更好地了解这些功能的运作方式,快速地挑选出你需要的功能。

View File

@@ -0,0 +1,38 @@
---
home: true
title: 首页
heroImage: /images/logo.svg
actions:
- text: 快速上手
link: /zh-cn/guide/home
type: primary
- text: 更新日志
link: /zh-cn/about/changelog
type: secondary
features:
- title: 轻量优雅
details: 拥有一套强大、优雅、人性化、完全使用 Kotlin lambda 打造的 API可以帮你快速实现字节码的过滤以及反射功能。
- title: 全面兼容
details: 使用原生 Java API 实现反射功能,可在任何 Kotlin on JVM 的项目上使用,在 Android 上使用也丝毫不成问题。
- title: 快速上手
details: 简单易用,不需要繁琐的配置,不需要十足的开发经验,搭建环境集成依赖即可立即开始使用。
footer: Apache-2.0 License | Copyright (C) 2019 HighCapable
---
### 随时随地,开始反射。
```java
public class World {
private void sayHello(String content) {
System.out.println("Hello " + content + "!");
}
}
```
```kotlin
World().resolve().firstMethod {
name = "sayHello"
parameters(String::class)
}.invoke("KavaRef")
```

View File

@@ -0,0 +1,768 @@
# kavaref-core
![Maven Central](https://img.shields.io/maven-central/v/com.highcapable.kavaref/kavaref-core?logo=apachemaven&logoColor=orange&style=flat-square)
<span style="margin-left: 5px"/>
![Maven metadata URL](https://img.shields.io/maven-metadata/v?metadataUrl=https%3A%2F%2Fraw.githubusercontent.com%2FHighCapable%2Fmaven-repository%2Frefs%2Fheads%2Fmain%2Frepository%2Freleases%2Fcom%2Fhighcapable%2Fkavaref%2Fkavaref-core%2Fmaven-metadata.xml&logo=apachemaven&logoColor=orange&label=highcapable-maven-releases&style=flat-square)
这是 KavaRef 的核心依赖,你需要引入此模块才能使用 KavaRef 的基本功能。
## 配置依赖
你可以使用以下方式将此模块添加到你的项目中。
### SweetDependency (推荐)
在你的项目 `SweetDependency` 配置文件中添加依赖。
```yaml
libraries:
com.highcapable.kavaref:
kavaref-core:
version: +
```
在你的项目 `build.gradle.kts` 中配置依赖。
```kotlin
implementation(com.highcapable.kavaref.kavaref.core)
```
### Version Catalog
在你的项目 `gradle/libs.versions.toml` 中添加依赖。
```toml
[versions]
kavaref-core = "<version>"
[libraries]
kavaref-core = { module = "com.highcapable.kavaref:kavaref-core", version.ref = "kavaref-core" }
```
在你的项目 `build.gradle.kts` 中配置依赖。
```kotlin
implementation(libs.kavaref.core)
```
请将 `<version>` 修改为此文档顶部显示的版本。
### 传统方式
在你的项目 `build.gradle.kts` 中配置依赖。
```kotlin
implementation("com.highcapable.kavaref:kavaref-core:<version>")
```
请将 `<version>` 修改为此文档顶部显示的版本。
## 功能介绍
你可以 [点击这里](kdoc://kavaref-core) 查看 KDoc。
### 基本用法
KavaRef 采用链式调用的设计方案,它对可用的 Java 反射 API (例如 `Class`) 创建了扩展方法,你只需要对这些内容调用 `resolve()`,即可进入 KavaRef 的世界。
关系图如下。
``` :no-line-numbers
KavaRef
└── KClass/Class/Any.resolve()
├── method()
├── constructor()
└── field()
```
接下来,我们将给出多个示例的 Java `Class`,后续都将基于它们进行基本的反射方案讲解。
```java :no-line-numbers
package com.demo;
public class BaseTest {
public BaseTest() {
// ...
}
private void doBaseTask(String taskName) {
// ...
}
}
```
```java :no-line-numbers
package com.demo;
public class Test extends BaseTest {
private Test() {
// ...
}
private static TAG = "Test";
private boolean isTaskRunning = false;
private void doTask(String taskName) {
// ...
}
private void release(String taskName, Function<boolean, String> task, boolean isFinish) {
// ...
}
private void stop() {
// ...
}
private String getName() {
// ...
}
}
```
```java
public class Box<T> {
public void print(T item, String str) {
// ...
}
}
```
假设,我们想要得到 `Test` 的 `doTask` 方法并执行,在 KavaRef 中,你可以通过以下方式来实现。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val test: Test
// 通过实例化 Class 的方式对其进行反射
// 在 KavaRef 中,你无需将其转换为 `java.lang.Class`
// 它会自动调用 KClass.java
Test::class
// 创建 KavaRef 反射
.resolve()
// 创建 Method (方法) 条件
.method {
// 设置方法名
name = "doTask"
// 设置方法参数类型
parameters(String::class)
}
// 条件执行后会返回匹配到的 List<MethodResolver> 实例
// 这里我们获取到过滤结果的第一个
.first()
// 在 MethodResolver 上设置 Test 的实例
.of(test)
// 调用方法并传入参数
.invoke("task_name")
```
在以上写法中,我们通过 `Test::class.resolve()` 来获取当前 `Class` 的 KavaRef 反射实例,
然后通过 `method { ... }` 来创建一个方法过滤条件 `MethodCondition`,在其中设置方法名和参数类型,执行后返回 `List<MethodResolver>` 实例,
接着我们通过 `first()` 来获取第一个匹配到的 `MethodResolver` 实例,
然后通过 `of(test)` 来设置当前 `Class` 的实例,最后通过 `invoke("task_name")` 来执行方法并传入参数。
在这其中,`MethodCondition` 继承自 `MemberCondition`,它允许你对 `Method` 进行条件筛选,其中包含了 Java 核心的反射 API 的条件镜像,你可以查看对应的注释来了解每个 API 的原生用法。
同样地,`MethodResolver` 继承自 `MemberResolver`,它允许你对过滤结果中的 `Method` 进行反射调用。
由于这里的反射需求是得到一个可用的方法结果,所以 `method { ... }.first()` 的调用链可能来起来会比较繁琐,这个时候就有以下简化方案。
> 示例如下
```kotlin
Test::class
.resolve()
// 直接使用 firstMethod 来获取第一个匹配到的 MethodResolver 实例
.firstMethod {
name = "doTask"
parameters(String::class)
}
.of(test)
.invoke("task_name")
```
由于我们现在可以拿到 `Test` 的实例,那么还有一种简化写法,你可以直接使用这个实例创建 KavaRef 反射。
> 示例如下
```kotlin
// 在这里Test 的实例 test 会被传给 KavaRef 并获取 test::class.java
test.resolve()
.firstMethod {
name = "doTask"
parameters(String::class)
} // 由于你设置了实例,所以这里不再需要 of(test)
.invoke("task_name")
```
接下来,我们需要得到 `isTaskRunning` 变量,可以写作以下形式。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val test: Test
// 使用 KavaRef 调用并执行
val isTaskRunning = test.resolve()
.firstField {
name = "isTaskRunning"
type = Boolean::class
}.get<Boolean>()
```
`Test` 中的构造方法是私有化的,现在,我们可以使用以下方式来创建它的实例。
> 示例如下
```kotlin
val test = Test::class.resolve()
.firstConstructor {
// 对于零参构造方法,可以使用以下条件过滤
// 它等价于 parameterCount = 0
emptyParameters()
}.create() // 创建一个新的 Test 实例
```
你也可以使用 `createAsType<T>()` 为实际对象 `Test` 指定其超类类型 `BaseTest`。
> 示例如下
```kotlin
val test = Test::class.resolve()
.firstConstructor {
emptyParameters()
}.createAsType<BaseTest>() // 创建一个新的 BaseTest 实例
```
::: tip
除了 `firstMethod` 等方法外,你也可以使用 `lastMethod` 等方法来获取最后一个匹配到的 `MethodResolver` 实例,它等价于 `method { ... }.last()`。
在得到 `MemberResolver` 实例后,你可以使用 `self` 来获取当前 `MemberResolver` 的 `Member` 原始实例来对其进行一些你自己的操作。
在继承于 `InstanceAwareResolver` 的 `MemberResolver` 中 (例如 `MethodResolver` 和 `FieldResolver`),你都可以使用 `of(instance)`
来设置当前实例,如果反射得到的是静态 (static) 成员,你无需设置实例。
:::
::: danger
在继承于 `InstanceAwareResolver` 的 `MemberResolver` 中,`of(instance)` 的类型要求与当前反射的 `Class` 实例泛型类型相同,
除非不指定 `Class` 泛型类型,或将 `Class` 泛型类型设置为 `Any`。
如果 `of(instance)` 出现 `Required: Nothing?` 错误 (这通常由于 `Class` 通过 `Class.forName(...)` 或 `ClassLoader.loadClass(...)` 创建)
则是你的 `Class` 为 `Class<*>` (Java 中是 `Class<?>`),此时如果你不想指定类型,请设置或转换为 `Class<Any>`,就像下面这样。
> 示例如下
```kotlin
val myClass = Class.forName("com.xxx.MyClass") as Class<Any>
// 假设这就是这个 Class 的实例
val myClassInstance: Any
myClass.resolve()
.firstMethod {
// ...
}.of(myClassInstance).invoke(...)
```
你也可以使用 [kavaref-extension](kavaref-extension.md) 中提供的 [创建 Class 对象](kavaref-extension.md#创建-class-对象) 来解决这个问题。
:::
### 模糊条件
你会注意到 `Test` 中有一个 `release` 方法,但是它的方法参数很长,而且部分类型可能无法直接得到。
此时,你可以借助 `parameters(...)` 条件使用 `VagueType` 来填充你不想填写的方法参数类型。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val test: Test
// 使用 KavaRef 调用并执行
test.resolve()
.firstMethod {
name = "release"
// 使用 VagueType 来填充不想填写的类型,同时保证其它类型能够匹配
parameters(String::class, VagueType, Boolean::class)
} // 得到这个方法
```
::: warning
`VagueType` 只能在有多个参数的过滤条件时使用,它不可以在只能设置单个参数的过滤条件中使用,例如 `type`。
你可以使用 `VagueType`、`VagueType::class` 或 `VagueType::class.java` 来创建,它们都能被正确识别为模糊过滤条件。
:::
### 自由条件
在 `MemberCondition` 中,`name`、`type`、`parameterCount` 等条件都可以使用 Kotlin lambda 特性创建自由过滤条件。
假设我们要得到 `Test` 中的 `doTask` 方法,可以使用以下实现。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val test: Test
// 使用 KavaRef 调用并执行
test.resolve()
.firstMethod {
// 使用 lambda 来设置方法名
name {
// 设置名称不区分大小写
it.equals("dotask", ignoreCase = true)
}
// 设置参数类型
parameters(String::class)
}.invoke("task_name")
```
### 泛型条件
KavaRef 支持添加泛型过滤条件,你可以使用 `TypeMatcher` 提供的相关功能来实现。
假设我们需要过滤 `Box<String>` 中的 `print` 方法。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val box: Box<String>
// 使用 KavaRef 调用并执行
box.resolve()
.firstMethod {
name = "print"
// 设置泛型参数条件
genericParametes(
// 过滤泛型名称 "T"
typeVar("T"),
// 通过 Class 创建 TypeMatcher
String::class.toTypeMatcher()
)
}.invoke("item", "str")
```
### 在超类过滤
你会注意到 `Test` 继承于 `BaseTest`,现在我们想得到 `BaseTest` 的 `doBaseTask` 方法。
在不知道超类名称的情况下,我们只需要在过滤条件中加入 `superclass()` 即可实现这个功能。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val test: Test
// 使用 KavaRef 调用并执行
test.resolve()
.firstMethod {
name = "doBaseTask"
parameters(String::class)
// 只需要添加这个条件
superclass()
}.invoke("task_name")
```
这个时候我们就可以在超类中获取到这个方法了。
::: tip
`superclass()` 一旦设置就会自动循环向后过滤全部继承的超类中是否有这个方法,直到过滤到目标没有超类 (继承关系为 `java.lang.Object`) 为止。
:::
::: danger
当前过滤的方法除非指定 `superclass()` 条件,否则只能过滤到当前 `Class` 的方法,这是 Java 反射 API 的默认行为,
KavaRef 会调用 `Class.getDeclaredMethods()` 来获取当前 `Class` 的方法而不是 `Class.getMethods()`。
:::
### 更多条件
KavaRef 提供了一些过滤条件来辅助 Java 反射 API 的使用。
假设我们要得到 `Test` 中的静态变量 `TAG` 的内容。
为了体现过滤的条件包含静态描述符 (static),我们可以使用以下方式来实现。
> 示例如下
```kotlin
val tag = Test::class.resolve()
.firstField {
name = "TAG"
type = String::class
// 创建描述符过滤
modifiers(Modifiers.STATIC)
// 或者
modifiers {
it.contains(Modifiers.STATIC)
}
}.get<String>() // 获取字段内容
```
你还可以在 `type`、`parameters` 等条件中使用字符串类型传入完整类名。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val test: Test
// 使用 KavaRef 调用并执行
test.resolve()
.firstMethod {
name = "doTask"
// 使用字符串类型传入完整类名
parameters("java.lang.String")
}.invoke("task_name")
```
### 异常处理
在默认情况下KavaRef 会在反射调用过程中找不到成员时抛出异常。
> 示例如下
```kotlin
Test::class.resolve()
.method {
name = "doNonExistentMethod"
} // 这里会抛出 NoSuchMethodException
```
如果你不希望抛出异常,可以设置可选条件 `optional()`。
> 示例如下
```kotlin
Test::class.resolve()
// 设置可选条件
.optional()
.method {
name = "doNonExistentMethod"
} // 返回空的 List<MethodResolver>
```
KavaRef 会打印完整的异常内容以供调试,在使用 `optional()` 时,异常会以 WARN 级别的日志打印。
> 示例如下
``` :no-line-numbers
No method found matching the condition for current class.
+------------------------------------------------+
| class com.demo |
+------------+-----------------------------------+
| name | doNonExistentMethod |
| parameters | [class java.lang.String, boolean] |
+------------+-----------------------------------+
```
如果你不希望 KavaRef 抛出或打印任何内容,你可以使用 `optional(silent = true)` 静默化处理,但是我们**不建议这样做**,这会掩盖问题,除非有必要这么做。
::: danger
如果你设置了 `optional()`,那么请不要使用 `firstMethod`、`firstConstructor` 等方法来获取单个结果,
因为它们会在没有结果时抛出列表为空的异常,你可以使用后缀为 `OrNull` 的方法来获取单个结果。
:::
### 日志管理
KavaRef 提供了其自身的日志管理功能,你可以通过 `KavaRef.logLevel` 来设置日志级别。
你可以设置 `KavaRef.logLevel = KavaRefRuntime.LogLevel.DEBUG` 来启用 DEBUG 级别的日志使得 KavaRef 在过滤过程向控制台打印更为详细的分步过滤条件日志。
如果你想关闭 KavaRef 的全部日志打印,你可以设置 `KavaRef.logLevel = KavaRefRuntime.LogLevel.OFF`。
如果你有更高级的需求,你可以实现 `KavaRefRuntime.Logger` 来自定义自己的日志打印方式。
> 示例如下
```kotlin
class MyLogger : KavaRefRuntime.Logger {
// 在这里可以指定日志打印的标签
override val tag = "MyLogger"
override fun debug(msg: Any?, throwable: Throwable?) {
// 在这里实现你的日志打印逻辑
}
override fun info(msg: Any?, throwable: Throwable?) {
// 在这里实现你的日志打印逻辑
}
override fun warn(msg: Any?, throwable: Throwable?) {
// 在这里实现你的日志打印逻辑
}
override fun error(msg: Any?, throwable: Throwable?) {
// 在这里实现你的日志打印逻辑
}
}
```
然后,将其设置到 KavaRef 上即可。
> 示例如下
```kotlin
KavaRef.setLogger(MyLogger())
```
### 进阶用法
上述内容讲解的均为标准场景下的使用方法,如果你有更加细粒度的使用场景,你可以手动创建 KavaRef 的相关组件。
如果你不喜欢 Kotlin lambda 的写法,你可以手动创建链式调用。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val test: Test
// 使用 KavaRef 调用并执行
test.resolve()
.method() // 条件开始
.name("doTask")
.parameters(String::class)
.build() // 条件结束 (执行)
.first()
.invoke("task_name")
```
你还可以手动创建任何过滤条件以实现在任何反射中复用它。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val test: Test
// 手动创建 MethodCondition
val condition = MethodCondition<Test>()
condition.name = "doTask"
condition.parameters(String::class)
// 应用条件到反射对象
Test::class.resolve()
.firstMethod(condition)
.of(test) // 设置实例
.invoke("task_name")
```
或者,你还可以手动完整地实现整个反射过程。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val test: Test
// 手动创建 MethodCondition
val condition = MethodCondition<Test>()
condition.name = "doTask"
condition.parameters(String::class)
// 手动创建 MemberCondition.Configuration
val configuration = Test::class.java.createConfiguration(
memberInstance = test, // 设置实例
processorResolver = null, // 使用默认的解析器,可参考下方的 "自定义解析器"
superclass = false, // 是否在超类中过滤
optional = MemberCondition.Configuration.Optional.NO // 配置可选条件
)
// 创建并开始过滤
val resolvers = condition.build(configuration)
// 获取第一个结果
val resolver = resolvers.first()
// 执行方法
resolver.invoke("task_name")
```
如果你对业务层逻辑有更高级的需求,你还可以使用 `mergeWith` 来合并多个过滤条件。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val test: Test
// 手动创建 MethodCondition
// 创建第一个条件
val condition1 = MethodCondition<Test>()
condition1.name = "doTask"
// 创建第二个条件
val condition2 = MethodCondition<Test>()
condition2.parameters(String::class)
// 将 condition2 合并到 condition1 中
// 此时 condition1 的条件将包含 condition2 不为 null 的条件,
// condition1 中重复的条件将被 condition2 的条件覆盖
condition1.mergeWith(condition2)
// 你还可以使用 infix 语法
condition1 mergeWith condition2
// 使用 KavaRef 调用并执行
Test::class.resolve()
.firstMethod(condition1)
.of(test)
.invoke("task_name")
```
::: danger
当 `MemberCondition` 已经设置 `MemberCondition.Configuration` 时将不再允许重复使用 `build(...)` 进行创建,
此时你需要使用 `copy()` 来复制并创建一份新的 `MemberCondition`。
同样地,`InstanceAwareResolver` 在通过 `MemberCondition.Configuration.memberInstance` 或 `of(instance)` 设置实例后也不允许重复设置新的实例,
此时你也需要使用 `copy()` 来复制并创建一份新的 `InstanceAwareResolver`。
:::
### 自定义解析器
KavaRef 使用默认的 `Member` 解析器进行过滤操作,如果你想实现自己的解析器,你可以自定义全局和每一个反射过程使用的解析器。
你可以继承于 `MemberProccessor.Resolver` 来实现自己的解析器。
> 示例如下
```kotlin
class MyMemberProcessorResolver : MemberProcessor.Resolver() {
override fun <T : Any> getDeclaredConstructors(declaringClass: Class<T>): List<Constructor<T>> {
// 在这里拦截并实现你的构造方法过滤逻辑
return super.getDeclaredConstructors(declaringClass)
}
override fun <T : Any> getDeclaredMethods(declaringClass: Class<T>): List<Method> {
// 在这里拦截并实现你的方法过滤逻辑
return super.getDeclaredMethods(declaringClass)
}
override fun <T : Any> getDeclaredFields(declaringClass: Class<T>): List<Field> {
// 在这里拦截并实现你的字段过滤逻辑
return super.getDeclaredFields(declaringClass)
}
}
```
然后你可以将其设置到全局配置中。
> 示例如下
```kotlin
MemberProcessor.globalResolver = MyMemberProcessorResolver()
```
或者,在每次反射过程中,你可以使用 `MemberCondition.Configuration` 来设置自定义解析器,或者使用链式调用设置解析器。
> 示例如下
```kotlin
// 创建解析器
val myResolver = MyMemberProcessorResolver()
// 假设这就是这个 Class 的实例
val test: Test
// 使用 KavaRef 调用并执行
test.resolve()
// 设置自定义解析器
.processor(myResolver)
.firstMethod {
name = "doTask"
parameters(String::class)
}.invoke("task_name")
```
::: tip
你可以在 [这里](../config/processor-resolvers.md) 找到一些公开维护的自定义解析器,定义在你的项目中即可使用。
:::
### 关于缓存
由于过滤条件的多样性KavaRef 不直接提供缓存功能,根据每个开发者的实现方式不同,缓存的实现方式也会有所不同。
我们建议手动对过滤结果创建的 `MemberResolver` 实现缓存以提高性能并参考 [手动创建](#手动创建) 拆分过滤条件以优化代码复用率。
::: danger
如果你使用了 `val myResolver by lazy { ... }` 来实现缓存,例如下方这样做。
> 示例如下
```kotlin
val myResolver by lazy {
Test::class.resolve()
.firstMethod {
name = "doTask"
parameters(String::class)
}
}
```
你在调用时可能会这样做。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val test: Test
// 使用 KavaRef 调用并执行
myResolver.of(test).invoke("task_name")
```
请注意,由于 `MemberResolver` 已被缓存,在你每次引用它时调用的是同一个实例,而 `MemberResolver` 的实例对象不允许重复设置 (参考 [手动创建](#手动创建) 下方的 “特别注意”)
所以直接这样调用会抛出异常,你需要改为以下形式。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val test: Test
// 使用 KavaRef 调用并执行
myResolver.copy().of(test).invoke("task_name")
```
这样一来,你就可以在每次调用时复制一个新的 `MemberResolver` 实例而不需要重复反射过程,也不会抛出异常。
:::
### Java 用法
KavaRef 不推荐直接在 Java 中使用,因为它的 API 设计是基于 Kotlin 的特性和语法糖。
如果你需要在 Java 中使用 KavaRef你可以使用以下方式来实现。
> 示例如下
```java
public class Main {
public static void main(String[] args) {
// 假设这就是这个 Class 的实例
Test test;
// 使用 KavaRef 调用并执行
KavaRef.resolveClass(Test.class)
.method()
.name("doTask")
.parameters(String.class)
.build()
.get(0)
.of(test)
.invoke("task_name");
// 或者,使用实例创建 KavaRef 反射
KavaRef.resolveObject(test)
.method()
.name("doTask")
.parameters(String.class)
.build()
.get(0)
.invoke("task_name");
}
}
```

View File

@@ -0,0 +1,295 @@
# kavaref-extension
![Maven Central](https://img.shields.io/maven-central/v/com.highcapable.kavaref/kavaref-extension?logo=apachemaven&logoColor=orange&style=flat-square)
<span style="margin-left: 5px"/>
![Maven metadata URL](https://img.shields.io/maven-metadata/v?metadataUrl=https%3A%2F%2Fraw.githubusercontent.com%2FHighCapable%2Fmaven-repository%2Frefs%2Fheads%2Fmain%2Frepository%2Freleases%2Fcom%2Fhighcapable%2Fkavaref%2Fkavaref-extension%2Fmaven-metadata.xml&logo=apachemaven&logoColor=orange&label=highcapable-maven-releases&style=flat-square)
这是 KavaRef 相关功能的扩展依赖。
## 配置依赖
你可以使用如下方式将此模块添加到你的项目中。
### SweetDependency (推荐)
在你的项目 `SweetDependency` 配置文件中添加依赖。
```yaml
libraries:
com.highcapable.kavaref:
kavaref-extension:
version: +
```
在你的项目 `build.gradle.kts` 中配置依赖。
```kotlin
implementation(com.highcapable.kavaref.kavaref.extension)
```
### Version Catalog
在你的项目 `gradle/libs.versions.toml` 中添加依赖。
```toml
[versions]
kavaref-extension = "<version>"
[libraries]
kavaref-extension = { module = "com.highcapable.kavaref:kavaref-extension", version.ref = "kavaref-extension" }
```
在你的项目 `build.gradle.kts` 中配置依赖。
```kotlin
implementation(libs.kavaref.extension)
```
请将 `<version>` 修改为此文档顶部显示的版本。
### 传统方式
在你的项目 `build.gradle.kts` 中配置依赖。
```kotlin
implementation("com.highcapable.kavaref:kavaref-extension:<version>")
```
请将 `<version>` 修改为此文档顶部显示的版本。
## 功能介绍
你可以 [点击这里](kdoc://kavaref-extension) 查看 KDoc。
### Class 扩展
KavaRef 提供了一些扩展,在处理 `Class` 对象时会更加方便。
KavaRef 对 `Class` 的扩展同样添加了 `KClass` 扩展,作用是调用 `KClass.java`,写法上比直接使用 `Some::class.java` 更加简洁。
#### 创建 Class 对象
例如我们需要使用字符串类名创建一个 `Class` 对象。
> 示例如下
```kotlin
val myClass = "com.example.MyClass".toClass()
// 你可以使用带有 OrNull 后缀的方法在找不到 Class 时返回 null 而不是抛出异常
val myClassOrNull = "com.example.MyClass".toClassOrNull()
```
这些方法统一使用 `ClassLoaderProvider` 来获取默认的 `ClassLoader`,你可以设置默认的 `ClassLoader` 以影响全局功能。
> 示例如下
```kotlin
ClassLoaderProvider.classLoader = MyCustomClassLoader()
```
你也可以手动向 `toClass` 方法传入一个 `ClassLoader` 参数来指定使用哪个 `ClassLoader`
#### Class 对象引用
在 Kotlin 中引用 Java Class 需要写很长的声明,例如 `MyClass::class.java`,此时你可以用以下方式来简化。
> 示例如下
```kotlin
val myClass = classOf<MyClass>()
```
你可以使用 `isSubclassOf` 方法来判断一个 `Class` 是否是另一个 `Class` 的子类。
> 示例如下
```kotlin
val isSubclass = MyClass::class isSubclassOf MySuperClass::class
// 当然它也有一个对应的反义判断方法
val isNotSubclass = MyClass::class isNotSubclassOf MySuperClass::class
```
你还可以使用 `hasSuperclass``hasInterfaces` 方法来判断一个 `Class` 是否有超类或接口。
::: danger
`classOf` 方法传入的 `Class` 默认会进行 Java 包装类的拆箱操作,无论你传入的是类似 `kotlin.Boolean` 还是 `java.lang.Boolean` (参考下方的 [Java 包装类扩展](#java-包装类扩展))
如果你需要避免传入的 `Class` 被拆箱变为原始类型,你需要明确设置 `primitiveType = false` 参数。
:::
#### 创建新的实例
KavaRef 为 `Class` 提供了一个方法来方便地创建一个新的实例,你不需要考虑构造参数的类型,你只需要传入对应的参数即可立即创建一个新的实例。
> 示例如下
```kotlin
val myClass = MyClass::class.createInstance("Hello", 123)
// 你也可以使用带有 OrNull 后缀的方法在创建失败时返回 null 而不是抛出异常
val myClassOrNull = MyClass::class.createInstanceOrNull("Hello", 123)
// createInstance 方法默认仅过滤公开的构造方法,如果你需要调用非公有构造方法,请设置 isPublic = false
val myClassWithPrivateConstructor = MyClass::class.createInstance("Private!", isPublic = false)
// 如果你想指定创建实例的类型使用另一个类型,可以使用以下方法
val mySuperClass = MyClas::class.createInstanceAsType<MySuperClass>("Hello", 123)
// 同样地,你也可以使用带有 OrNull 后缀的方法在创建失败时返回 null 而不是抛出异常
val mySuperClassOrNull = MyClass::class.createInstanceAsTypeOrNull<MySuperClass>("Hello", 123)
```
::: tip
`createInstance` 方法在成功匹配一次后,会将结果进行缓存防止重复反射造成的性能损耗,它是线程安全的,你可以放心在任何标准场景下使用。
:::
::: danger
当你传入带有 `null` 的参数时KavaRef 会尝试将其作为可匹配到条件的一部分 (模糊条件),准确性可能会下降。
`createInstance` 方法不允许所有参数均为 `null` 的情况 (条件完全模糊),会直接抛出异常,因为这种情况无法确定要创建哪个实例。
:::
#### Class 修饰符
KavaRef 也对 `Modifier` 进行了扩展,你可以直接使用 `Class.isPublic` 等方法来判断一个 `Class` 的修饰符。
#### VariousClass
KavaRef 提供了 `VariousClass` 类来装载不确定完整类名的 `Class` 对象,并返回成功匹配到的第一个。
此功能通常可用于 Android 应用中那些被 R8 混淆后的类名。
> 示例如下
```kotlin
// 假设在 A 版本中,这个类为 com.example.a
// 在 B 版本中,这个类为 com.example.b
val myClass = VariousClass("com.example.a", "com.example.b").load()
// 你也可以使用后缀名为 OrNull 的方法在找不到 Class 时返回 null 而不是抛出异常
val myClassOrNull = VariousClass("com.example.a", "com.example.b").loadOrNull()
```
#### 延迟装载 Class 对象
KavaRef 提供了 `LazyClass` 类来延迟装载 `Class` 对象。
你可以在需要时再装载 `Class`,而不是在创建时就立即装载,这可以解决一些需要运行时或运行到特定条件下才需要装载的 `Class`
> 示例如下
```kotlin
// 定义一个不可为空延迟装载的 Class 并托管给 myClass
val myClass by lazyClass("com.example.MyClass")
// 定义一个可为空延迟装载的 Class 并托管给 myClassOrNull
val myClassOrNull by lazyClassOrNull("com.example.MyClass")
// 它亦可支持传入 VariousClass
val otherClassOrNull by lazyClassOrNull(VariousClass("com.example.a", "com.example.b"))
// 在需要时调用即装载
myClass.resolve()
myClassOrNull?.resolve()
otherClassOrNull?.resolve()
```
#### ClassLoader 扩展
KavaRef 还为 `ClassLoader` 提供了一些实用的扩展方法。
> 示例如下
```kotlin
// 假设这就是你的 ClassLoader
val classLoader: ClassLoader
// 装载一个 Class在装载失败时返回 null
val myClassOrNull = classLoader.loadClassOrNull("com.example.MyClass")
// 判断这个 Class 是否存在于当前 ClassLoader 中
val isClassExists = classLoader.hasClass("com.example.MyClass")
```
### 数组 Class 扩展
在 Java 中,数组的 `Class` 对象是一个特殊的 `Class` 对象,通常,我们创建它的方式如下。
例如创建一个 `java.lang.String[]``Class` 对象。
> 示例如下
```kotlin
val arrayClass = java.lang.reflect.Array.newInstance(String::class.java, 0).javaClass
```
这样写起来非常长,而且不方便维护,所以 KavaRef 提供了一个方法来简化这个过程。
现在,创建 `java.lang.String[]``Class` 对象可以这样写。
> 示例如下
```kotlin
val arrayClass = ArrayClass(String::class)
```
### Member 扩展
KavaRef 提供了一些扩展方法来简化对 `Member` 的操作。
你可以在任何 `Member` 对象上使用 `makeAccessible` 方法来设置其可访问性。
如果 `Member``AccessibleObject` 类型即可生效。
> 示例如下
```kotlin
// 假设这个是你当前的 Member 对象
val method: Method
// 设置方法可访问
method.makeAccessible()
```
同样地KavaRef 也对 `Modifier` 进行了扩展,你可以直接使用 `Member.isPublic` 等方法来判断一个 `Member` 的修饰符。
### Type 扩展
在 Java 中操作类型或泛型类型时,通常需要使用 `Type` 接口及其子接口来处理。
KavaRef 提供了一些扩展方法来简化对 `Type` 的操作。
例如,你可以将一个符合要求的 `Type` 转换为 `Class` 对象。
> 示例如下
```kotlin
val type: Type
val clazz = type.toClass()
// 你也可以使用后缀名为 OrNull 的方法在转换失败时返回 null 而不是抛出异常
val clazzOrNull = type.toClassOrNull()
```
你也可以将符合要求的 `Type` 转换为 `ParameterizedType` 对象。
> 示例如下
```kotlin
val type: Type
val parameterizedType = type.asParameterizedType()
// 你也可以使用后缀名为 OrNull 的方法在转换失败时返回 null 而不是抛出异常
val parameterizedTypeOrNull = type.asParameterizedTypeOrNull()
```
你还可以使用以下方式获取超类中的泛型参数数组,这在一些超类与子类的封装操作中会经常用到。
> 示例如下
```kotlin
val myClass: Class<*>
// 获取 myClass 的超类的泛型参数数组,获取失败或无法获取时将返回空数组
val arguments = myClass.genericSuperclassTypeArguments()
```
### Java 包装类扩展
在 Kotlin 中直接使用 `Boolean::class``Byte::class` 等方式获取到的是 Java 的原始类型 `boolean``byte` 而不是它们的包装类。
如果你需要获取 Java 的包装类,你需要使用完整的 `java.lang.Boolean::class``java.lang.Byte::class` 等方式或使用 `Boolean::class.javaObjectType``Byte::class.javaObjectType`
所以KavaRef 提供了一些类型别名来处理 Java 的包装类,现在你只需要在这些类型加上 `J` 前缀即可,例如 `JBoolean::class`
它等价于 `java.lang.Boolean::class`,部分类型需要填写全称,例如 `JInteger::class`