Java中宏定义的等价物是什么?

3

我的问题与这个问题类似,但并不完全相同。

我在我的类中有一个继承来的参数数组(意思是,我不能/不想改变它),就像这样:

public double[] params;

这个类会以复杂的方式使用这些参数,所以我更喜欢为数组中的每个元素使用易于理解的名称。在C语言中,你可以这样做。

#define MY_READABLE_PARAMETER params[0]

我知道在Java中,我可以创建一堆常量或带有属性的枚举类型。然后,要访问一个参数,我需要输入类似以下的内容:

params[MY_READABLE_PARAMETER]

这样是可以的,但我真的很想完全省略数组名称。这可能吗?

2
有各种Java预处理器支持C风格的宏。 - Jochen Bedersdorfer
@Jochen 这种情况使用这么大材小用的方法不会太过了吗? - Naurgul
过度杀伤?这就是C预处理器正在做的“过度杀伤”... - Jochen Bedersdorfer
@Jochen 我的意思是我必须安装一个额外的库才能实现这个小便利。如果这是必须的,并且我需要一个复杂的宏,那么我想这样做也没问题。 - Naurgul
4个回答

3

是的,只要不使用数组就可以实现:

double myReadableParameter;
double anotherReadableParameter;

如果您需要将它们作为集合访问,您可以将它们放在列表中。


我很想这样做,但正如我所说,这个数组是继承来的。我不能干扰父类,尤其是因为在一般情况下我们不知道有多少参数。 - Naurgul
好的,我认为我的答案仍然适用 - 您可以在派生类的构造函数中分配可读参数。 - Karel Petranek
@toto 父类不知道有多少个实例,但在派生类中指定。这是遗传算法的全部内容,如果有帮助的话。因此,父类是抽象的个体,而我的类是我正在解决的具体问题的个体。 - Naurgul
@Naurgul:是的,你需要这样做,有问题吗?除非你使用Double(作为类)而不是原始double类型,否则你无法避免这个问题。 - Karel Petranek
@dark_charlie 很不幸,这是一个大问题。我正在开发的应用程序将同时拥有数十个或数百个此类实例。我真的不能承受一切都要重复的情况。 - Naurgul
显示剩余5条评论

3

你有什么不能做到的原因吗?

...
public double getMyReadableParam() {
    return params[0];
}

public void setMyReadableParam(double value) {
    params[0] = value;
}
...

不,这肯定是可行的。我会考虑一下。谢谢! - Naurgul
转念一想,如果我有20个参数,那就意味着要新建40个方法来调整名称。不太优雅。 - Naurgul
我同意,增加40个新方法会显得不简洁。在我看来,无论如何,依赖于一个任意的双精度数组而没有逻辑连接会导致不简洁;无论你做什么,我认为你都必须接受某些不简洁之处。 - Ben

3

使用 Enum

enum Param {
    AGE(0);
    WEIGHT(1);
    ...

    private int arrayIndex;
    // Constructor
    Param(int index) {
        arrayIndex = index;
    }

    public double getValue(double[] params) {
        return params[arrayIndex];
    }
}

然后您可以像这样使用它

double age = Param.AGE.getValue(params);

我认为这并不比其他建议更好,但我想展示如何使用ENUM实现它。


实际上,类似于枚举或常量的东西,例如public static int THE_ANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING = 42; - Joe Plante
糟糕,上一条评论没有完成。无论如何,公共静态常量和枚举是常见的做法,我认为枚举被认为稍微好一些。 - Joe Plante

1
如果您有一个双精度数组,并且每个特定位置的数组元素具有明确的含义,那么您应该创建一个类来代替。
public class MyParamBlob extends ParentParamBlob
{
    private double myReadableParameter;
    private double anotherParameter;
    private double yetOneMore;

    // getters and setters as appropriate
}

如果您需要从“外部”处理现有的double[],您可以编写一个构造函数和/或一个将数组作为参数的方法。
public class MyParamBlob
{
    ...
    public MyParamBlob(double[] values)
    {
        setAll(values);
    }
    // getters and setters as appropriate
    ...
    public void setAll(double[] values)
    {
        myReadableParameter = values[0];
        anotherParameter = values[1];
        // etc.
    }
}

编辑 - 解释我的评论

如果这个子类的原始父类(双重[]存在的原因)有一个获取数组的getter方法,那么可以在此类中对其进行覆盖,并在请求时构建和返回数组。例如:

public double[] getParams()
{
    double[] params = new double[4];
    params[0] = myReadableParameter;
    params[1] = anotherParameter;
    // etc.
}

如果数组可以从父类实例中直接访问,而不需要getter方法,例如myArray = parentInstance.params或者double d2 = parentInstance.params[2],那么(1)这是一个糟糕的设计,(2)调用者可以在你的情况下改变数组中的值。parentInstance.params[1] = 0.0;

你的第二个解决方案不会导致数据存储两次吗?一次在values中,一次在MyParamBlob的字段中。 - Naurgul
我认为存储空间并不重要。无论如何,您拥有的任何解决方案都将占用一些内存。然而,拥有两个参数副本的危险在于当您尝试为它们分配新值时可能会产生大错误。 - toto2
@Naurgul - 不,注意数组是作为参数传递而不是存储的;只有其中的值被存储。真正重要的是,与toto的评论相关的是数组是否可以在父类中访问,可以通过public double[] getParams()或直接parentThing.params[2]来访问,在这种情况下,您可能需要将数组与实例成员同步。但对于getParams(),您可以在请求时构建和返回数组...请参见我的编辑。 - Stephen P
我喜欢覆盖方法的想法,使它看起来像有一个数组,但实际上并没有。然而,在父类中,该数组是公共的,但它也有一个getter/setter对。我不确定用什么与我的代码之外的类进行交互。我也不确定你所说的“调用者可以从下面更改数组值parentInstance.params[1] = 0.0;”是什么意思。 - Naurgul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接