如何基于cmd args初始化静态final变量?

5

我的课程作业要求我为一个静态final变量分配一个可选的cmd参数。

我已经尝试在main()中进行操作,但编译器报错“无法为最终变量赋值”。我尝试在由main()调用的静态方法中进行操作,但是出现了相同的错误。我听说过其他答案中使用静态块,但我需要在决定要分配什么时能够访问cmd参数。我还困扰于参数解析,因为两个参数都应该有默认值,除非提供了其中一个。任何额外的建议都非常受欢迎。

public class FibonacciNim {
    private static Scanner myScanner = new Scanner(System.in);
    private static final int NO_OF_HEAPS;
    private static final int TOKENS_PER_HEAP;

    public static void main(String[] args) {
        // set heaps and tokens using args
        if (args.length == 0) {
            NO_OF_HEAPS = 3;
            TOKENS_PER_HEAP = 9;
        } else {
            boolean usageCorrect = false;
            for (int i = 0; i < args.length-1; i++) {
                if (args[i].equals("-heaps")) {
                    try {
                        NO_OF_HEAPS = Integer.parseInt(args[i+1]));
                        usageCorrect = true;
                    } catch (NumberFormatException e) {
                        usageCorrect = false;
                    }
                } else if (args[i].equals("-tokens")) {
                    try {
                        TOKENS_PER_HEAP = Integer.parseInt(args[i+1]);
                        usageCorrect = true;
                    } catch (NumberFormatException e) {
                        usageCorrect = false;
                    }
                }
            }
        }

        ...

    }

    ...

}

感谢您的阅读!

静态变量真的需要是final吗? - assylias
嘿,看起来是个好问题!欢迎!所以final可能是Java中预定义的关键字,你也可以尝试在main函数内定义这些变量,因为它们在这里超出了作用域。 - Sweet Chilly Philly
2个回答

5

您无法从命令行实际上真正地将某个值分配给一个静态不可变变量。(您也许可以通过极其肮脏的黑客手段实现,但这可能不是分配任务的本意。)

可能的做法是创建一个可变的静态不可变变量并将其分配给其中的内容。这是非常糟糕的做法,在实际生活中您真的不应该这样做,但至少是可行的。例如,您可以编写:

static final String[] argHolder = new String[1];
public static void main(String[] args) {
  ...
  argsHolder[0] = args[0];
  ...
}

我喜欢这个想法,除了我的简要说明说: “只需更改一个或多个静态变量即可更改程序中令牌堆的数量”。 - Bob
1
在这种情况下,您应该创建不是final的静态变量。 - Louis Wasserman
或者将它们转换为可变的静态常量变量。 - locus2k
本意是输入“一个或多个静态常量变量”。 - Bob
那真是非常奇怪。我认为除了我描述的方法之外,没有其他方法可以使其工作。 - Louis Wasserman
显示剩余2条评论

4

静态常量变量只能在初始化时进行赋值。

public class MyClass {

  private static final int NO_OF_HEAPS = 3;

}

非静态 final 变量可以在一行中或构造函数中被赋值:

public class MyClass {

  private final int NO_OF_HEAPS;

  public MyClass() {
    NO_OF_HEAPS = 9;
  }

}

你可以将静态变量设置为“本质上”是final的,方法是将它们更改为可变项,例如AtomicInteger

public class FibonacciNim {
  private static Scanner myScanner = new Scanner(System.in);
  private static final AtomicInteger NO_OF_HEAPS = new AtomicInteger(0);
  private static final AtomicInteger TOKENS_PER_HEAP = new AtomicInteger(0);

  public static void main(String[] args) {
    // set heaps and tokens using args
    if (args.length == 0) {
        NO_OF_HEAPS.set(3);
        TOKENS_PER_HEAP.set(3);
    }
    ...
  }
}

在解析命令行参数方面,您可以查看 JCommander http://jcommander.org/

它提供了解析命令行参数并填充POJO以供使用的功能,因此您不必自己解析它们。


我选择了这个选项,但我的教授反馈说他认为AtomicInteger是用于线程相关工作的。 - Bob
从技术上讲,他是正确的,通常它们就是用于那个目的,但这并不意味着它们只能用于那个目的。如所述,如果您需要一个静态的、最终的可变对象,您需要像 AtomicInteger 这样的东西,因为 intInteger 是不可变对象。 - locus2k

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