[知乎回答] Java中为为什么给float类型变量赋值需要加F,而给byte、short赋值的时候却不需要呢?

刷知乎的时候回答了一个提问,写在博客里记录一下知乎地址:
java中为为什么给float类型变量赋值需要加F,而给byte、short赋值的时候却不需要呢? - 知乎 (zhihu.com)

最近刚好在看《Java虚拟机规范》,对这类提问挺感兴趣的。在查阅百度之后,我发现一篇博客https://www.jianshu.com/p/726eef453af9其中写道:

1
2
3
4
5
6
7
8
9
10
11
public class Test {
public static void main(String[] args){
float f1 = 6.6f;
float f2 = 1.3f;
System.out.println(f1 + f2);

double f3 = 6.6;
double f4 = 1.3;
System.out.println(f3 + f4);
}
}

相信不少人都会一口说出答案——两个7.9然而这个答案是错误的!!!对于double类型和float类型,是两个完全不同的概念,相同数值的Float和Double在Java中二进制数也是不一样的。


为什么byte类型可以直接使用int赋值?

因为在Java中,byte类型是直接被编码成int类型来存储。为什么?Java就是这么设计的,我也不知道。如何得到这个结论的?我亲自通过javap -c xxx.class查看字节码 得到的。接下来上代码

1
2
3
4
5
6
7
public class Test{
public static void main(){
byte a = 1;
a+=1;
System.out.println(a);
}
}

JVM字节码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Compiled from "Test.java"
public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iload_1
3: iconst_1
4: iadd
5: i2b
6: istore_1
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
14: return
}

通过查阅JVM虚拟机字节码指令表我们可知:

字节码助记符指令含义
0x04iconst_1将int型1推送至操作数栈顶
0x3cistore_1将操作数栈顶int型数值存入第二个本地变量表
iload_1将第二个int型本地变量表推送至操作数栈顶
0x60iadd将操作数栈顶两int型数值相加并将结果压入操作数栈顶
0x91i2b将操作数栈顶int型数值强制转换为byte型数值并将结果压入操作数栈顶

我们可以看到,在Java中存储一个byte是通过操作int的指令来完成的。所以byte与int之间可以直接进行计算操作。所以可以不用显示的声明这个byte a = 1中的1是byte类型。


什么是操作数栈,什么是本地变量表?

可以看我的博客:https://blog.mcplugin.cn/p/699