Skip to content

Shadow

在 Mixin 类中,被 @Shadow 注解的成员相当于一个占位符。注解成员会“李代桃僵”,成为目标类中某一本就存在的成员的替身。你可以正常地在 Mixin 类中引用、调用,而不受目标类中对应真实成员的权限约束。

参数

remap: [可选,参数类型为 Boolean,默认值为 true]

若此项值为 false,注解处理器(annotation processor)则会跳过该成员的 remap 处理。在使用 @Shadow注解模组成员时,需要将 remap 设置为 false,但在处理原版 Minecraft 成员时则需要为 true。

aliases: [可选,参数类型为 String Array,默认值为 {}]

你可以在 Array 中填入此成员的别名(aliases),这一参数可用于某些合成成员(synthetic member),或是某些在运行时受其他来源影响而名称发生变化的成员。

prefix: [可选,参数类型为 String,默认值为 "shadow$"]

编译器并不会允许同名且同参数方法的存在,即使它们的返回类型不同也不行。在你使用 @Shadow 的过程中,这一限制可能会为你带来些许麻烦。但无需紧张,你可以使用 prefix 来解决。当 Mixin 类运行时,使用了 prefix 的成员会自动剔除自身标记的“前缀”,这样就绕开了编译的限制。

java
public class Illegal {
    protected String method(String argument) {
        return "";
    }

    protected int method(String argument) {
        return 0;
    }
}

public class Legal {
    @Shadow(prefix = "alt$")
    protected String alt$method(String argument) {
        return "";
    }

    protected int method(String argument) {
        return 0;
    }
}

用法

使用 @Shadow 注解字段

java
public class Target {
    private static String privateStaticString = "Hello Static World";

    private String privateValue = "Hello World";

    protected int protectedValue = 42;
}
java
@Mixin(Target.class)
public class Example {
    @Shadow private static String privateStaticString = ""; // 不会影响目标类中的真实字段

    @Shadow private String privateValue = null; // 不会影响目标类中的真实字段

    @Shadow protected int protectedValue = 0; // 不会影响目标类中的真实字段
}

Shadowing a Method

java
public class Target {
    public static void staticMethod() {
        // ...
    }

    public void method() {
        // ...
    }

    public int fruitfulMethod() {
        // ...
    }
}

使用 @Shadow 注解方法

java
public class Target {
    public static void staticMethod() {
        // ...
    }

    public void method() {
        // ...
    }

    public int fruitfulMethod() {
        // ...
    }
}
java
@Mixin(Target.class)
public class Example {
    @Shadow public static void staticMethod() { }

    @Shadow public void method() { }

    // 如果这一方法有返回值,
    // 那你可以将返回值直接设置为某一基本类型,或是直接为null。
    // 但最好还是抛出一个异常,以免遇到某些极端情况。
    @Shadow public int fruitfulMethod() {
        throw new AssertionError();
    }
}
java
@Mixin(Target.class)
// 你也可以直接将使用了 @Shadow 注解的方法写为抽象方法,这样便无需关注此方法的具体实现了
// 但你也得相对应地将 Mixin 类改为抽象类
public abstract class AbstractExample {
    // 静态方法不可为抽象,因为它们与“类”同级!
    // 参照 Example.java,
    // 静态方法也可以写成如下这样,也是用于避免极端情况。
    @Shadow public static void staticMethod() {
        throw new AssertionError();
    }

    @Shadow public abstract void method();

    @Shadow public abstract int fruitfulMethod();
}

贡献者

页面历史

© 2024 CleanroomMC. All Rights Reserved.