====== 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 = "(Lsome/random/package/Outer;)V", at = @At("HEAD") private void injected(CallbackInfo ci) { // 你的代码 } **2. 静态无法访问的内部类** 与上述方式一样, 唯一的区别在于构造方法不需要在第一个参数指明外部类类型(因为在静态内部类中只能访问外部类的静态方法). **3. 匿名内部类** 与静态无法访问的内部类方式一样, 唯一区别在于他们没有名称, 所以是按照出现的顺序声明的, 举例: 如果前面的例子中第一个被声明的名称是Outer$1, 第二个的名称则是Outer$2, 第三个的名称则是Outer$3(声明顺序是源码级别的). ** 施工中 **