我写了一个常量文件。
public interface IConstants {
int SOME_CONSTANT = 6;
}
我写了一个包装方法来访问ConstantWrapper文件中的“SOME_CONSTANT”变量
public class ConstantWrapper {
static ConstantWrapper mConstantWrapper = null;
private ConstantWrapper(){
}
public static ConstantWrapper getInstance(){
if(mConstantWrapper == null)
mConstantWrapper = new ConstantWrapper();
return mConstantWrapper;
}
public int getSomeConstantValue(){
return IConstants.SOME_CONSTANT;
}
}
现在,我想在switch case语句中访问包装方法,但我得到错误“需要常量表达式”。如何解决这个问题?
public class DemoClass{
private void checkSwitchCases(int value) {
switch (value){
case ConstantWrapper.getInstance().getSomeConstantValue(): // I get the error "constant expression required" in this line
System.out.println("Case 6");
break;
case 8:
System.out.println("Case 8");
break;
default:
System.out.println("Case default");
break;
}
}
}
你在这里应用了各种各样的反模式。看起来你遇到了一个问题(这里:我有一些我想管理的常量),并决定了一个问题的解决方案(一个接口,一个你错误地称为“包装器”的类),现在正在就你在实现解决方案时遇到的问题提出进一步的问题。但是,这不是一个好的解决方案,所以让我们回到最初的问题。
我写了一个常量文件
把一堆常量塞进一个接口过去很常见,但是现在我们有了枚举是星型导入,这不再是推荐的方法。只要把你的常量放在它们最相关的地方(不太可能是一个接口,但是如果你必须这样做,好吧)-并使用导入静态com.foo。ThatType。*;
在一个想要使用它们的类中。不要在任何地方实现你的I常量
-你的类的类型层次结构是公共信息,应该说明一些关于结构的事情,I常量
毫无意义,这就是为什么这是坏风格。
I常量
不推荐这种匈牙利符号变体。如果您发现某个类型是相关的,您的IDE完全有能力通知您该类型是接口还是类。您不应该一开始就认为这是相关的代码:为什么IName
是反模式的两个很好的理由。
类ConstantWrapper
这样做的目的是什么?为了维护ConstantWrapper类,你已经为自己做了大量的工作。我能猜测的唯一真正的好处是,你可以选择插入一个替代实现,但这意味着这些常量实际上首先不是常量,因此你得到的错误是正确的,解决方案是根本不使用开关
,并且通常停止使用术语“常量”。将一个有一堆角的东西称为“圆形”是个坏主意。命名很难,但很重要。
公共静态ConstantWrapper getInstance()
你没有应用双重锁定,这意味着你可以有2个或更多的ConstantWrapper实例。如果你必须动态加载一个类,你应该依赖类加载器。然而,使用实际初始化的getInstance
方法绝对没有任何意义:java不会在启动时加载所有类;它只是在第一次使用时加载一个类。鉴于ConstantWrapper
的“首次使用”将是. getInstance()
,java已经会在你想要的时候完全启动它们。因此:
public class ConstantWrapper {
private static final ConstantWrapper INSTANCE = new ConstantWrapper();
public static ConstantWrapper getInstance() {
return INSTANCE;
}
}
这完全实现了您想要的(即,只有1个实例,并且该实例在需要之前不会初始化),但现在代码更少,并且没有错误。
常量表达式所需错误
方法调用不能是常量表达式周期。来源:Java语言规范。
如果初始化表达式是常量的,则在声明时初始化的静态和最终字段,其类型为原始或字符串,并且null
不是常量表达式。这就是它结束的地方。所以,这工作:
class Example {
public static final int FOO = 5;
}
class Foo {
{
switch (value) {
case Example.FOO: // allowed; this is a constant expression
case 10: // allowed; this is constant too
}
}
}
甚至像静态最终int A=5, B=10,C=A B;
这样的东西也是允许的(C
在这里也是常量,因为编译器可以在编译时弄清楚),但编译器不会走得太远。
没有办法让方法调用算作常量表达式,也没有办法告诉switch
接受非常量表达式。