Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/348.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JLS是否需要最终字符串常量的内联?_Java_Java 8_Language Lawyer_Javac_Jls - Fatal编程技术网

Java JLS是否需要最终字符串常量的内联?

Java JLS是否需要最终字符串常量的内联?,java,java-8,language-lawyer,javac,jls,Java,Java 8,Language Lawyer,Javac,Jls,我在操作某些字节码时遇到了一个问题,java编译器(java 8)没有内联某个final字符串常量,请参见下面的示例: public class MyTest { private static final String ENABLED = "Y"; private static final String DISABLED = "N"; private static boolean isEnabled(String key) { return key.equals("A

我在操作某些字节码时遇到了一个问题,java编译器(java 8)没有内联某个
final
字符串
常量,请参见下面的示例:

public class MyTest
{
  private static final String ENABLED  = "Y";
  private static final String DISABLED = "N";

  private static boolean isEnabled(String key) {
      return key.equals("A");
  }

  private static String getString(String key, String value) {
      return key + value;
  }

  public static void main(String[] args) throws Exception {
    String flag = getString("F", isEnabled("A") ? ENABLED : DISABLED);
    System.out.println(flag);

    String flag2 = getString("F", isEnabled("A") ? ENABLED : DISABLED);
    System.out.println(flag2);
  }
}
使用javac生成的字节码(1.8.0_101)

您可以看到,在第二次访问字段
ENABLED
DISABLED
时,编译器没有内联它们的值(使用
ldc
),而是使用
getstatic
直接访问字段。用其他编译器(Java7、Eclipse)测试它不会触发相同的行为,并且常量总是内联的


这可能被认为是编译器错误,还是根据JLS允许不始终内联字符串常量?

是的,“内联”行为由规范强制执行:

  • 对常量变量(§4.12.4)字段的引用必须在编译时解析为常量变量初始值设定项表示的值
    V

    如果此类字段是静态的,则二进制文件中的代码中不应存在对该字段的引用,包括声明该字段的类或接口。此类字段必须始终显示为已初始化(§12.4.2);绝不能遵守字段的默认初始值(如果与
    V
    )的规定

    如果此类字段是非静态的,则二进制文件中的代码中不应存在对该字段的引用,包含该字段的类除外。(它将是一个类而不是一个接口,因为接口只有
    静态
    字段。)该类应该有代码在实例创建期间将字段的值设置为
    V
    (§12.5)

  • 请注意,这如何精确地解决您的场景:“如果这样一个字段是
    静态的
    ,那么二进制文件中的代码中不应该存在对该字段的引用,包括声明该字段的类或接口”

    换句话说,如果您遇到一个编译器不遵守此规则,您会发现一个编译器错误


    作为附录,查找这些信息的起点是:

    常量变量是原语类型或类型为
    String
    final
    变量,用常量表达式()初始化。变量是否为常量变量可能涉及类初始化()、二进制兼容性(、)和确定赋值()


    定义“内联”。JLS需要共享。这就是您所说的吗?内联意味着用直接将常量值推送到堆栈上的指令替换getstatic指令,例如字符串情况下的ldc,或iconst_X/bipush/sipush/。。。对于整数原语,…@piet.t:我删除了字节码标记,因为语言规范实际上不处理字节码。然而,行为的定义没有歧义,这就允许回答这个问题。这确实是一个bug,它已经被JDK 9中集成的修复程序修复,并被后传到JDK 1.8.0_102,即1.8.0_101加上一个补丁集。请注意,JDK-8066871有不同的症状,但相同的修复程序纠正了该错误以及此处描述的错误。我刚刚提交了一份错误报告(JI-9043578),因为我在错误数据库中没有找到相关条目。我想它可以关闭了。非常感谢,这正是我想要的,因此这证实了观察到的行为确实是一个编译器错误。我检查了所有这些引用,除了二进制兼容性:)
    public static void main(java.lang.String[]) throws java.lang.Exception;
        descriptor: ([Ljava/lang/String;)V
        flags: ACC_PUBLIC, ACC_STATIC
        Code:
          stack=2, locals=3, args_size=1
             0: ldc           #8                  // String F
             2: ldc           #2                  // String A
             4: invokestatic  #9                  // Method isEnabled:(Ljava/lang/String;)Z
             7: ifeq          16
            10: getstatic     #10                 // Field ENABLED:Ljava/lang/String;
            13: goto          19
            16: getstatic     #11                 // Field DISABLED:Ljava/lang/String;
            19: invokestatic  #12                 // Method getString:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
            22: astore_1
            23: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
            26: aload_1
            27: invokevirtual #14                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            30: ldc           #8                  // String F
            32: ldc           #2                  // String A
            34: invokestatic  #9                  // Method isEnabled:(Ljava/lang/String;)Z
            37: ifeq          46
            40: getstatic     #10                 // Field ENABLED:Ljava/lang/String;
            43: goto          49
            46: getstatic     #11                 // Field DISABLED:Ljava/lang/String;
            49: invokestatic  #12                 // Method getString:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
            52: astore_2
            53: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
            56: aload_2
            57: invokevirtual #14                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            60: return