java - 如何使用在编译时设置的动态数量的参数创建 java 方法(类似 lombok 的行为)

标签 java methods parameters enums parameter-passing

我想制作一个消息枚举,每条消息都在枚举类型上,以避免消息键中的拼写错误。我还想使用参数(如 #{0})来插入名称和更多信息。 为了让事情变得更简单,我想添加方法 get,它有一个动态数量的(字符串类型的)参数 - 每个我想要替换的参数都有一个。参数的确切数量应在编译时设置,并由该枚举值的字段定义。

考虑这个枚举:

public enum Message {
    // Written by hand, ignore typos or other errors which make it not compile.

    NO_PERMISSION("no_permission", 0),
    YOU_DIED("you_died", 1),
    PLAYER_LEFT("player_left", 2);

    private String key;
    private int argAmount;

    Message(String key, int argAmount) {
        this.key = key;
        this.argAmount = argAmount;
    }

    public String replace(String... args) {
        String message = get();
        for (int i = 0; i < args.length; i++) {
            message.replace("#{" + i + "}", args[i]);
        }

        return message;        
    }

    public String get() {
        return myConfigFileWrapper.getMessage(key);
    }
}

当我想检索消息时,我使用 Message.YOU_DIED.replace(myInformation)。但是,我必须查找 YOU_DIED 消息需要多少个参数,如果有多个,我需要查看配置文件以查看哪个索引属于哪个参数类型。

为了阐明这一点,这里有一个例子: PLAYER_LEFT 消息被广播给所有玩家并告诉他们玩家 x 已经离开,得分为 y。在我的 .lang 文件中,可以找到 player_left= The player #{0} left with the score #{1}!。在源代码中,我将需要使用 Message.PLAYER_LEFT.replace(name, score)。现在扩展我的枚举时,我可能有 100 多条消息。 这意味着我根本不记得消息是 The player #{0} left with the score #{1}! 还是 The player #{1} just left! .

我的目标是,当 get 方法未提供所需的确切参数数量时,编译器会自动抛出错误。这也意味着我的 IDE 自动完成功能会告诉我要传递多少参数。

如您所见,目前我正在使用可变参数将变量信息注入(inject)到消息中。为什么我想更进一步,现在应该很清楚了。我知道这是一种奢侈的功能,但我只是在学习,没有人期望在某个时间得到某种结果。

一种方法是使用具有大量子类的 Message 类来覆盖具有一组参数的原始 get 方法:get(String name, String score)。然而,这会使数十亿个子类变得一团糟——每条消息一个。我什至没有尝试创建这种 Message 类。此外,使用这种方式需要付出很多努力才能“创建”所有消息,然后再添加新消息。

接下来,我查看了反射 API 以使其正常工作,但当我发现反射不适用于动态编译时方法时,我就继续了。据我所知,实际上创建新的动态方法(这基本上是我尝试做的)是不可能的,尤其是因为无法通过正常调用使用它们,因为该方法在编译时不存在。

到目前为止,我所知道的唯一执行此操作的应用程序是 Lombok。 Lombok 使用在编译时用字节代码替换的注释。我查看了源代码,但只是核心本身相当大,并且到处都有交叉依赖,这使得很难真正理解发生了什么。

使用在编译时设置的动态参数编号生成这些方法的最佳和最简单方法是什么?这种方式是如何运作的?

非常感谢代码片段和指向包含更多信息的页面的链接。

最佳答案

您可以通过为每个不同数量的参数创建一个通用子类来限制子类的数量:

public class Message {
    public static final Message0Args NO_PERMISSION = new Message0Args("no_permission");
    public static final Message1Arg YOU_DIED = new Message1Arg("you_died");
    public static final Message2Args PLAYER_LEFT = new Message2Args("player_left");

    private String key;
    private int argAmount;

    protected Message(String key, int argAmount) {
        this.key = key;
        this.argAmount = argAmount;
    }

    // Same replace() method, but make it protected
}

子类例如:

public class Message2Args extends Message {
    public Message2Args(String key) {
        super(key, 2);
    }

    public String replace(String first, String second) {
        return super.replace(first, second);
    }   
}

请注意,Message 不再是一个 enum,但对于所有实际用途而言,它以相同的方式工作(具有一些额外的灵 active ,例如子类化),因为 enum 只是一个类的语法糖,该类的唯一实例包含在它自己的 public static final 字段中。

关于java - 如何使用在编译时设置的动态数量的参数创建 java 方法(类似 lombok 的行为),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30446608/

相关文章:

amazon-web-services - Cloudformation - 在 EC2 服务器中使用参数

JAVA hibernate/webservice - 时间戳问题

java - 部署数据库时出错

javascript - 我的 ajax post 方法有效,但我无法通过 php 捕获该值

actionscript-3 - ActionScript 3 覆盖方法 + 提高可见性

php - 如何在PHP中获取类的任何方法的输入参数?

jenkins - 将 'build with parameters' 从管道中的 scm 传递到 Jenkinsfile

sql - 如何在 SQL 脚本文件中使用参数

java - 一个枚举问题

java - 在 Java 中执行外部命令的经典问题?