【问题标题】:Non-static variable in case expression?案例表达式中的非静态变量?
【发布时间】:2011-07-13 22:36:45
【问题描述】:

我想从另一个类中访问一个公共整数,以便在 switch 语句中使用,如下所示:

StateManager sm = new StateManager(0);

switch (localState) {
    case (sm.ALL_COMPANIES_REQUEST): {
       //do something 
    }
    case (sm.GENERAL_TICKER_REQUEST): {
       //do this instead    
    }

但是,这些变量需要被多个线程访问,所以我不想让它们成为静态的。不幸的是,我收到一个错误,说 case 表达式必须是常量。没有改变这些变量的方法,它们是恒定的,但似乎如果不标记它们static,计算机就无法弄清楚这一点。有谁知道如何解决这个问题?

编辑: 嵌套类怎么样,这是一个选项,因为 StateManager 只对上面带有 switch 语句的类有用。这足以单独使用 final 吗?

【问题讨论】:

    标签: java static switch-statement


    【解决方案1】:

    要求switch语句上的值是常量表达式或枚举值;见JLS 14.11

    JLS 15.28 中描述了一个常量表达式。本质上它是一个编译时间 常量表达式。所以这意味着这样的东西不会编译:

        static final int foo = someString.length();
        ...
        switch (x) {
            case foo: ...  // case label is not a >>compile time<< constant
        }
    

    但是,您对静态常量和线程的担忧是没有根据的。 final 字段的规范特别声明它们可以在不同步的情况下安全地读取;见JLS 17.5

    (此外,即使字段不是最终的,您也不会遇到死锁。如果线程没有正确同步,您会得到线程可能看到字段的陈旧值父对象或类。)

    所以你的问题的答案是:

    • 如果常量是编译时常量,你可以直接声明为static final,switch语句会编译,但是
    • 如果该常量不是编译时常量,则将其声明为 static final 将无济于事。

    嵌套类怎么样?

    这不会有任何区别。

    【讨论】:

      【解决方案2】:

      如果它们是常量,那么声明它们 final static 并在 case 语句中使用它们是没有问题的。多线程在这里没有影响。

      【讨论】:

      • 哦,好吧,我认为这可能会导致线程锁定。感谢您的帮助!
      • 您认为使用多线程的静态 final 会出现问题的假设是不正确的。
      【解决方案3】:

      为什么不在枚举中声明这些字段?

      enum Request { 
      
          ALL_COMPANIES,
          GENERAL_TICKER
      
      }
      

      然后在你的开关中使用它。

      【讨论】:

        【解决方案4】:

        尝试使用 final,这将使其保持不变。

        【讨论】:

        • 他们是最终的,不幸的是这还不够。也许是因为它们是在另一个类中定义的?我不确定..
        【解决方案5】:

        在按下开关之前在线使用static/static+final修饰符。

        void m(){
        final int a = 0;
        
        switch(e)
        case a : ...
        
        }
        

        不会工作,因为 void m() 将在所有静态属性/方法编译后编译。

        void m()
        {
        switch(e)
        case a : ...
        }
        
        final int a = 0;
        

        不会起作用,因为“a”的声明在开关之后

        final int a = 0;
        
        void m()
        {
        switch(e)
        case a : ...
        }
        

        会起作用的 .

        同样的原理

        static A a = new A(b);
        static B b = new B();
        

        无法正常工作,因为 JVM 构建器正在逐行读取代码......它不像 C/C++ 中那么糟糕,但它仍然存在。

        switch 适用于静态、最终常量、枚举...它们不适用于 hashSet 条目(这是让我非常生气的一件事:D)

        【讨论】:

        • switches 不是条件,它们在堆中有特殊的子树,因此您必须考虑这一点,并想象当您构建代码时,即使它看起来像“switch 在您的代码之前的这一行或那一行或在某些属性声明之后“物理上他们看不到对方,这就是它不起作用的原因。
        • 因此,如果您确定“这些将是您的常量”,请尝试使用枚举,或者尝试为您希望切换/大小写的每个条目使用带有静态常量的 Provider 类。
        猜你喜欢
        • 2010-09-19
        • 2016-12-29
        • 2014-02-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多