202 lines
5.6 KiB
Markdown
202 lines
5.6 KiB
Markdown
---
|
|
front:
|
|
hard: 进阶
|
|
time: 8分钟
|
|
---
|
|
|
|
|
|
# 便捷的反射工具
|
|
## 介绍
|
|
TabooLib 内置了专属的反射依赖库 [https://github.com/TabooLib/reflex](https://github.com/TabooLib/reflex)
|
|
Reflex 为基于 Kotlin 语言开发的反射工具,其与 Java 原生反射 API 及 kotlin-reflect 间最大区别在于其可无视软兼容反射目标类中的字段或方法。
|
|
你无需了解这么多 只需要看看有没有遇到这种情况:
|
|
1. 想获取一个private的变量
|
|
2. 想执行一个private的方法
|
|
|
|
## 用法
|
|
```kotlin
|
|
class TestNoEdit(){
|
|
private var a = 0
|
|
private fun say(){
|
|
println("say")
|
|
}
|
|
}
|
|
|
|
fun test(){
|
|
val test = TestNoEdit()
|
|
test.a = 1 // 并不可以这样
|
|
|
|
//
|
|
val property = test.getProperty<Int>("a") ?: 0
|
|
|
|
test.invokeMethod<Any>("say")
|
|
|
|
TestNoEdit::class.java.invokeConstructor()
|
|
}
|
|
```
|
|
至此 成为反射的神!
|
|
|
|
|
|
## 获取字段参数
|
|
```kotlin
|
|
test.getProperty<字段类型>("字段的名称")
|
|
// T:
|
|
val property = test.getProperty<Int>("a") ?: 0
|
|
```
|
|
|
|
那,老师 如果我不知道用什么字段类型应该怎么办?
|
|
可以使用 Any
|
|
|
|
```kotlin
|
|
test.getProperty<Any>("a")
|
|
```
|
|
|
|
## 设置字段内容
|
|
```kotlin
|
|
test.setProperty("字段的名称","要设置的值")
|
|
test.setProperty("a",10)
|
|
```
|
|
|
|
## 运行方法
|
|
```kotlin
|
|
invokeConstructor(构造函数的类型)
|
|
// 例如 构造函数需要两个字符串
|
|
invokeConstructor(String::class.java,String::class.java)
|
|
```
|
|
|
|
## 获取构造函数
|
|
```kotlin
|
|
invokeConstructor(构造函数的类型)
|
|
// 例如 构造函数需要两个字符串
|
|
invokeConstructor(String::class.java,String::class.java)
|
|
```
|
|
|
|
## 案例 - 扫包读取某class的注解进行注册 6.1
|
|
```kotlin
|
|
@Awake
|
|
object GermUIHook : ClassVisitor(5) {
|
|
|
|
// 在什么时机进行扫描
|
|
override fun getLifeCycle(): LifeCycle {
|
|
return LifeCycle.ENABLE
|
|
}
|
|
|
|
// 扫描类,同级的还有扫描方法 和 扫描常量的
|
|
override fun visitStart(clazz: Class<*>, instance: Supplier<*>?) {
|
|
// 判断是否实现了 IGermUI 接口
|
|
if (clazz.interfaces.contains(IGermUI::class.java)) {
|
|
// 判断是否这个类被 @HookGerm("value") 修饰
|
|
if (clazz.isAnnotationPresent(HookGerm::class.java)) {
|
|
// 获取注解 @HookGerm
|
|
val hook = clazz.getAnnotation(HookGerm::class.java)
|
|
// 取出内容并添加到 Map中
|
|
hookMap[hook.value] = clazz as Class<IGermUI>
|
|
} else {
|
|
val name = clazz.simpleName
|
|
hookMap[name] = clazz as Class<IGermUI>
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
```kotlin
|
|
/**
|
|
* 当类开始加载时
|
|
*
|
|
* @param clazz 类
|
|
* @param instance 实例
|
|
*/
|
|
public void visitStart(@NotNull Class<?> clazz, @Nullable Supplier<?> instance) {
|
|
}
|
|
|
|
/**
|
|
* 当类结束加载时
|
|
*
|
|
* @param clazz 类
|
|
* @param instance 实例
|
|
*/
|
|
public void visitEnd(@NotNull Class<?> clazz, @Nullable Supplier<?> instance) {
|
|
}
|
|
|
|
/**
|
|
* 当字段加载时
|
|
*
|
|
* @param field 字段
|
|
* @param clazz 类
|
|
* @param instance 实例
|
|
*/
|
|
public void visit(@NotNull ClassField field, @NotNull Class<?> clazz, @Nullable Supplier<?> instance) {
|
|
}
|
|
|
|
/**
|
|
* 当方法加载时
|
|
*
|
|
* @param method 方法
|
|
* @param clazz 类
|
|
* @param instance 实例
|
|
*/
|
|
public void visit(@NotNull ClassMethod method, @NotNull Class<?> clazz, @Nullable Supplier<?> instance) {
|
|
}
|
|
```
|
|
|
|
|
|
## 案例 - 扫包注册papi变量 6.2
|
|
```kotlin
|
|
@Awake
|
|
@Inject
|
|
class PlaceholderRegister : ClassVisitor(0) {
|
|
|
|
val hooked by unsafeLazy {
|
|
runCatching { Class.forName("me.clip.placeholderapi.expansion.PlaceholderExpansion") }.isSuccess
|
|
}
|
|
|
|
override fun visitStart(clazz: ReflexClass) {
|
|
if (hooked && clazz.structure.interfaces.any { it.name == PlaceholderExpansion::class.java.name }) {
|
|
val expansion = findInstance(clazz) as? PlaceholderExpansion ?: error("PlaceholderExpansion must have an instance")
|
|
if (!expansion.enabled) {
|
|
return
|
|
}
|
|
object : me.clip.placeholderapi.expansion.PlaceholderExpansion() {
|
|
|
|
override fun persist(): Boolean {
|
|
return true
|
|
}
|
|
|
|
override fun getIdentifier(): String {
|
|
return expansion.identifier
|
|
}
|
|
|
|
override fun getAuthor(): String {
|
|
return BukkitPlugin.getInstance().description.authors.toString()
|
|
}
|
|
|
|
override fun getVersion(): String {
|
|
return BukkitPlugin.getInstance().description.version
|
|
}
|
|
|
|
override fun onPlaceholderRequest(player: Player?, params: String): String {
|
|
return expansion.onPlaceholderRequest(player, params)
|
|
}
|
|
|
|
override fun onRequest(player: OfflinePlayer?, params: String): String {
|
|
return expansion.onPlaceholderRequest(player, params)
|
|
}
|
|
}.also { papiExpansion ->
|
|
// 自动重载
|
|
if (expansion.autoReload) {
|
|
registerBukkitListener(ExpansionUnregisterEvent::class.java) {
|
|
if (it.expansion == papiExpansion) {
|
|
submit { papiExpansion.register() }
|
|
}
|
|
}
|
|
}
|
|
}.register()
|
|
}
|
|
}
|
|
|
|
override fun getLifeCycle(): LifeCycle {
|
|
return LifeCycle.ENABLE
|
|
}
|
|
}
|
|
``` |