【问题标题】:Why isn't a final variable always a constant expression?为什么最终变量不总是一个常量表达式?
【发布时间】:2015-08-27 09:50:30
【问题描述】:

在下面的代码中:

final int a;
a=2;
byte b=a;   // error: possible loss of precision

为什么会出现此错误? a final 变量不是编译时常量表达式,因此在赋值期间隐式缩小为字节吗?

换句话说,上面的代码不等同于:

final int a=2;
byte b=a;

【问题讨论】:

    标签: java expression constants compile-time-constant narrowing


    【解决方案1】:

    来自JLS

    空白final 是一个final 变量,其声明缺少初始化程序。

    常量变量是基本类型或类型的final 变量 String 用常量表达式初始化(​​第 15.28 节)。

    你的变量

    final int a;
    

    是一个空白final变量。它缺少初始化程序。第二段不适用于它,因为它没有在声明时初始化。因此它不是一个常量表达式。

    这也适用于字段。

    【讨论】:

      【解决方案2】:

      编译器没那么聪明。

      我们可以看出该值将始终为 2。但是如果我们有这样的东西呢?

      class ABC{
          final int a;
      
          public ABC(){
             if(Math.random() < .5){
                a = 2;
             }
             else{
                a = 12345;
             }
      
             byte b = a;
          }
      }
      

      编译器不够聪明,无法区分这两种情况,所以它会给你一个错误。

      【讨论】:

      • 事实上编译器是不允许这么聪明的。
      • @usr 那里有一些严肃的原始宗教。严肃地说:这是为什么?编译器在乘法时对数字124 等很敏感。这个答案中的情况显然是无法解决的,因为从random 返回的值取决于程序启动的时间。
      • @LyingOnTheSky 但是即使计算是确定性的并且编译器可以计算出来,它仍然不允许将其视为常量表达式(消除对转换的需要)。重要的是,什么是或不是有效的 Java 程序并不取决于特定编译器的智能程度。
      • @CodesInChaos 你只是说编译器应该遵守标准。好点。
      • @LyingOnTheSky 差不多。在 C++ 中,编译器通常会添加自己的扩展。在 Java 中,它基本上是被禁止的(参见微软诉讼)。
      【解决方案3】:

      由于 final 变量可以延迟初始化,编译器无法确定 b 在 case 分支中有值。

      【讨论】:

        猜你喜欢
        • 2019-11-13
        • 2014-08-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-15
        • 1970-01-01
        • 1970-01-01
        • 2019-06-22
        相关资源
        最近更新 更多