【问题标题】:Java unary promotion, left shift operator, and shortJava一元提升、左移运算符和short
【发布时间】:2021-09-09 06:04:08
【问题描述】:

JLS §5.6.1 说:

某些运算符将一元数字提升应用于单个操作数,该操作数必须生成数字类型的值:
...
如果操作数是编译时类型 byte、short 或 char,则通过扩展原语转换将其提升为 int 类型的值
...
在以下情况下,会对表达式执行一元数值提升:
...
移位运算符 > 或 >>>

的每个操作数

这就解释了为什么这个程序无法编译:

public class xx {
    public short twice(short x) {
        return x << 1;
    }
}

出现此错误:

$ javac xx.java
xx.java:3: error: incompatible types: possible lossy conversion from int to short
        return x << 1;
                 ^
1 error

好的。那么为什么这个程序会编译成功呢?

public class xx {
    public short two() {
        return (short)1 << 1;
    }
}

表达式 (short)1 不符合“编译时类型字节、短或字符”的条件吗?

这是我正在使用的:

$ java -version
openjdk version "1.8.0_282"
OpenJDK Runtime Environment (build 1.8.0_282-bre_2021_01_20_16_37-b00)
OpenJDK 64-Bit Server VM (build 25.282-b00, mixed mode)

【问题讨论】:

  • 实际上,在函数 two() 中进行强制转换不会改变任何东西。我猜编译器将 1

标签: java javac jls


【解决方案1】:

我创建了与您类似的示例代码,然后检查了字节码。 代码如下:

package dsa;

public class Shorts {

    public static void main( String[] args ) {
        short what = twice();
        System.out.println(what);
    }
    
    public static short twice() {
        return 1 << 1;
    }
    
}

以及生成的字节码:

Compiled from "Shorts.java"
public class dsa.Shorts {
  public dsa.Shorts();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #7                  // Method twice:()S
       3: istore_1
       4: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
       7: iload_1
       8: invokevirtual #19                 // Method java/io/PrintStream.println:(I)V
      11: return

  public static short twice();
    Code:
       0: iconst_2
       1: ireturn
}

请注意,我不是专家,但在我看来,编译器优化函数返回常量整数,然后将其存储在 int 变量中,直到它被打印出来。所以答案是,套用一部著名电影的名言:“没有短片”。

【讨论】:

    【解决方案2】:

    演员阵容在这里是红鲱鱼;没有它,代码编译相同。重要的是表达式1 &lt;&lt; 1 是一个常量表达式。所以说 JLS ​(§5.2,强调我的):

    赋值上下文允许将表达式的值(第 15.26 节)赋值给变量;表达式的类型必须转换为变量的类型。 [...] 如果表达式是 byteshortcharint 类型的常量表达式(第 15.28 节):如果满足以下条件,则可以使用缩小原语转换变量的类型为byteshortchar,常量表达式的值可以用变量的类型来表示。

    请注意,您的表达式出现在 return 语句中,而不是变量赋值中,但 §14.17 告诉我们此表达式是一个赋值上下文,因此适用上面引用的 §5.2。

    所以你有一个short类型的赋值上下文,在那个上下文中你有一个常量表达式1 &lt;&lt; 1,它产生了2的值,它确实可以用short类型表示。这就是它编译的原因。

    【讨论】:

    • 谢谢。我认为这与作为一个常量表达式有关,但不知道这应该如何改变行为。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-02
    • 2013-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多