Table of Contents
Mixin 小提示
为什么使用抽象类?
1. 防止实例化
这么说吧, 你永远不应该将一个Mixin类实例化, 主要是因为脱离Mixin环境, 它对于程序的其他部分是没有意义的, 况且还有许多其他方式来访问Mixin类中定义的方法.
将一个Mixin类声明为抽象类并不会影响他的功能, 还能意外防止它被实例化, 可谓是两全其美.
MixinClass foo = new MixinClass(); // 抽象类则不能这样做
2. 更优雅的使用影子方法
如果你在mixin类中需要访问目标类中受限的方法/字段, 你需要使用@Shadow
使方法/字段可见.
在普通的类中, 你完全可以使用一个空方法体:
@Shadow private void hiddenMethod() {/*空方法体*/}
但是有更 优雅 方式, 也就是抽象方法 (并且修饰为抽象类):
@Shadow private abstract void hiddenMethod(); // 无需空方法体
3. 访问 “this” 实例
在Mixin中, 如果你想访问“this”实例, 你必须在mixin类中进行显式转换:
((TargetClass)(Object)this).字段/方法();
但是这一切都需要你的mixin类继承/实现所有目标类所做的一切才能行得通, 但是如果所继承/实现的类要求你实现方法, 可能会变成一个大麻烦.
幸运的是, 所有的事情都可以通过使用抽象类来回避, 在这种情况下, 你不必实现方法也就是说所有的问题都解决了.
如何Mixin内部类
1. 普通无法访问的内部类
因为你无法从外部直接访问这些类, 所以你需要使用Mixin注解的“targets”字段来指定名称.
你需要完整的写出外部类, 紧接着使用$
来连接外部类的完整路径和内部类的名称, 如下所示:
类:
package some.random.package; public class Outer { private class Inner { public void someRandomMethod() {} } }
使用注入的Mixin:
@Mixin(targets = "some.random.package.Outer$Inner") public class MyMixin { @Inject(method = "someRandomMethod()V", at = @At("HEAD") private void injected(CallbackInfo ci) { // 你的代码 } }
唯一需要注意的是, 如果你想对内部类构造方法动手脚, 则第一个形参必须为外部类类型(由编译器隐式添加以确保内部类可以访问外部类的私有方法):
@Inject(method = "<init>(Lsome/random/package/Outer;)V", at = @At("HEAD") private void injected(CallbackInfo ci) { // 你的代码 }
2. 静态无法访问的内部类
与上述方式一样, 唯一的区别在于构造方法不需要在第一个参数指明外部类类型(因为在静态内部类中只能访问外部类的静态方法).
3. 匿名内部类
与静态无法访问的内部类方式一样, 唯一区别在于他们没有名称, 所以是按照出现的顺序声明的, 举例: 如果前面的例子中第一个被声明的名称是Outer$1, 第二个的名称则是Outer$2, 第三个的名称则是Outer$3(声明顺序是源码级别的).
施工中