====== 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(声明顺序是源码级别的).
** 施工中 **