# 便捷的反射工具
# 介绍
TabooLib 内置了专属的反射依赖库 https://github.com/TabooLib/reflex (opens new window) Reflex 为基于 Kotlin 语言开发的反射工具,其与 Java 原生反射 API 及 kotlin-reflect 间最大区别在于其可无视软兼容反射目标类中的字段或方法。 你无需了解这么多 只需要看看有没有遇到这种情况:
- 想获取一个private的变量
- 想执行一个private的方法
# 用法
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()
}
至此 成为反射的神!
# 获取字段参数
test.getProperty<字段类型>("字段的名称")
// T:
val property = test.getProperty<Int>("a") ?: 0
那,老师 如果我不知道用什么字段类型应该怎么办?
可以使用 Any
test.getProperty<Any>("a")
# 设置字段内容
test.setProperty("字段的名称","要设置的值")
test.setProperty("a",10)
# 运行方法
invokeConstructor(构造函数的类型)
// 例如 构造函数需要两个字符串
invokeConstructor(String::class.java,String::class.java)
# 获取构造函数
invokeConstructor(构造函数的类型)
// 例如 构造函数需要两个字符串
invokeConstructor(String::class.java,String::class.java)
# 案例 - 扫包读取某class的注解进行注册 6.1
@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>
}
}
}
}
/**
* 当类开始加载时
*
* @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
@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
}
}
进阶
8分钟