2.6
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
---
|
||||
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
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user