mirror of
https://github.com/HighCapable/KavaRef.git
synced 2025-09-09 20:14:08 +08:00
Initial commit
This commit is contained in:
27
docs-source/src/zh-cn/about/about.md
Normal file
27
docs-source/src/zh-cn/about/about.md
Normal 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
|
21
docs-source/src/zh-cn/about/changelog.md
Normal file
21
docs-source/src/zh-cn/about/changelog.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# 更新日志
|
||||
|
||||
> 这里记录了 `KavaRef` 的版本更新历史。
|
||||
|
||||
::: danger
|
||||
|
||||
我们只会对最新的 API 版本进行维护,若你正在使用过时的 API 版本则代表你自愿放弃一切维护的可能性。
|
||||
|
||||
:::
|
||||
|
||||
## kavaref-core
|
||||
|
||||
### 1.0.0 | 2025.06.25  <Badge type="tip" text="最新" vertical="middle" />
|
||||
|
||||
- 首个版本提交至 Maven
|
||||
|
||||
## kavaref-extension
|
||||
|
||||
### 1.0.0 | 2025.06.25  <Badge type="tip" text="最新" vertical="middle" />
|
||||
|
||||
- 首个版本提交至 Maven
|
15
docs-source/src/zh-cn/about/contacts.md
Normal file
15
docs-source/src/zh-cn/about/contacts.md
Normal 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。
|
113
docs-source/src/zh-cn/about/future.md
Normal file
113
docs-source/src/zh-cn/about/future.md
Normal 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
|
||||
|
||||
以上功能可能会在实际推出后有所变化,最终以实际版本的功能为准。
|
||||
|
||||
:::
|
243
docs-source/src/zh-cn/config/migration.md
Normal file
243
docs-source/src/zh-cn/config/migration.md
Normal 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` 吧!
|
||||
|
||||
:::
|
38
docs-source/src/zh-cn/config/processor-resolvers.md
Normal file
38
docs-source/src/zh-cn/config/processor-resolvers.md
Normal 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
|
||||
}
|
||||
}
|
||||
```
|
5
docs-source/src/zh-cn/config/r8-proguard.md
Normal file
5
docs-source/src/zh-cn/config/r8-proguard.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# R8 与 Proguard 混淆
|
||||
|
||||
> 大部分场景下 Android 应用程序安装包可通过混淆压缩体积,这里介绍了混淆规则的配置方法。
|
||||
|
||||
`KavaRef` 在 Android 项目中不需要额外配置任何混淆规则。
|
36
docs-source/src/zh-cn/guide/home.md
Normal file
36
docs-source/src/zh-cn/guide/home.md
Normal 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)。
|
||||
|
||||
## 语言要求
|
||||
|
||||
推荐使用 Kotlin,API 代码构成同样支持 Java,但是在纯 Java 项目中 `KavaRef` 有可能无法发挥其全部功能和语法糖优势。
|
||||
|
||||
文档全部的 Demo 示例代码都将首先使用 Kotlin 进行描述,如果你完全不会使用 Kotlin 那你将有可能无法更全面地体验和使用 `KavaRef` 的功能。
|
||||
|
||||
## 功能贡献
|
||||
|
||||
本项目的维护离不开各位开发者的支持和贡献,目前这个项目处于初期阶段,可能依然存在一些问题或者缺少你需要的功能,
|
||||
如果可能,欢迎提交 PR 为此项目贡献你认为需要的功能或前往 [GitHub Issues](repo://issues) 向我们提出建议。
|
95
docs-source/src/zh-cn/guide/quick-start.md
Normal file
95
docs-source/src/zh-cn/guide/quick-start.md
Normal 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) 找到一些示例,查看对应的演示项目来更好地了解这些功能的运作方式,快速地挑选出你需要的功能。
|
38
docs-source/src/zh-cn/index.md
Normal file
38
docs-source/src/zh-cn/index.md
Normal 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")
|
||||
```
|
768
docs-source/src/zh-cn/library/kavaref-core.md
Normal file
768
docs-source/src/zh-cn/library/kavaref-core.md
Normal file
@@ -0,0 +1,768 @@
|
||||
# kavaref-core
|
||||
|
||||

|
||||
<span style="margin-left: 5px"/>
|
||||

|
||||
|
||||
这是 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");
|
||||
}
|
||||
}
|
||||
```
|
295
docs-source/src/zh-cn/library/kavaref-extension.md
Normal file
295
docs-source/src/zh-cn/library/kavaref-extension.md
Normal file
@@ -0,0 +1,295 @@
|
||||
# kavaref-extension
|
||||
|
||||

|
||||
<span style="margin-left: 5px"/>
|
||||

|
||||
|
||||
这是 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`。
|
Reference in New Issue
Block a user