zh_cn:tutorial:mixin_tips

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

施工中

zh_cn/tutorial/mixin_tips.txt · Last modified: 2022/08/14 15:35 by 127.0.0.1