java 8: class.getName() 和字符串字面量的区别

java 8: difference between class.getName() and String literal

我正在研究开关盒。

如果我们使用 class.getName(),那么,我得到如下错误 "case expressions must be constant expressions":

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

即使我们执行以下操作,将字符串 class 名称作为常量,然后也会出现相同的错误:

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";

谁能解释一下,为什么不取前两种情况而取最后一种?提前致谢。

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

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

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

A compile-time constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following:

  • Literals of primitive type and literals of type String

...

  • Simple names that refer to constant variables

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

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

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

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