【问题标题】:java 8: difference between class.getName() and String literal [duplicate]java 8:class.getName()和字符串文字之间的区别[重复]
【发布时间】:2015-11-11 08:11:34
【问题描述】:

我正在研究开关盒。

如果我们使用 class.getName(),那么,我会收到“case 表达式必须是常量表达式”的错误,如下所示:

switch(param.getClass().getName())
    {
        case String.class.getName():
            // to do
            break;
    }

即使我们执行以下操作,将字符串类名放入常量中,也会出现同样的错误:

public static final String PARAM_NAME = String.class.getName();
switch(param.getClass().getName())
    {
        case PARAM_NAME:
            // to do
            break;
    }

但是,如果我执行以下操作,使用字符串文字“java.lang.String”,则不会出现错误:

public static final String PARAM_NAME = "java.lang.String";

谁能解释一下,为什么不接受前两个案例并接受最后一个案例?提前致谢。

【问题讨论】:

    标签: java switch-statement java-8 constants string-literals


    【解决方案1】:

    classObject.getName() 是一个方法调用,根据定义,方法调用的结果不是编译时常量。字符串文字一个编译时常量。

    请注意,虽然许多情况下可以将 static final 引用作为程序生命周期的常量,但 switch 必须在编译时对其选项进行硬编码。 case 目标的值必须是枚举值或(编译时)ConstantExpression

    【讨论】:

    • 但是,我也在'static final'(即常量)变量中使用它,那么,它也不使用它吗?
    • 编译器做了一些神奇的事情,我假设前两件事被编译成完全相同的字节码。你给的最后一个,那里使用了字符串文字,因此它可以工作
    • @KrishnaKumar static final 字段不一定是编译时常量,即使出于实际目的它是运行时常量。
    • final 变量是编译时常量当且仅当它立即用编译时常量初始化。请注意,它不必是 static,它甚至不必是字段,该规则也适用于局部变量。
    【解决方案2】:

    每个 case 标签都必须是“常量表达式”。什么是“常量表达式”在 Java 语言标准中定义,§15.28 Constant Expressions

    编译时常量表达式是表示原始类型值或字符串的表达式,它不会突然完成并且仅使用以下内容组成:

    • 原始类型的文字和字符串类型的文字

    ...

    • 引用常量变量的简单名称

    那里没有列出任何方法调用,所以即使方法很平凡,方法调用结果也不能是常量表达式。但是这里列出了“引用常量变量的简单名称”,所以引用常量变量也是一个常量。

    【讨论】:

      【解决方案3】:

      这不起作用的原因是case 的值需要在编译时知道(因为它在字节码中是硬编码和内联的)。

      String.class.getName() 是一个在运行时评估的方法调用。是的,static final 保证在最初加载类后它不会改变。但这一切都在编译时间之后很久了。

      编译器从不调用来自应用程序源代码的任何代码(注释处理可能例外)。它只编译它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-17
        • 2011-03-18
        • 1970-01-01
        • 2016-10-22
        • 1970-01-01
        • 2020-03-28
        • 2016-07-14
        • 2018-11-12
        相关资源
        最近更新 更多