290,966
社区成员




目录
Java基本数据类型和其对应的包装类
bit(1字节) | Byte |
char(2字节) | Character |
short(2字节) | Short |
int(4字节) | Integer |
float(4字节) | Float |
double(8字节) | Double |
long(8字节) | Long |
boolean() | Boolean |
自动将基本数据类型转换为包装器类型
// 自动装箱 相当于 Integer a = Integer.valueOf(66);
Integer a = 66;
自动将包装器类型转换为基本数据类型
Integer i = new Integer(100);
// 自动拆箱 相当于 int n = i.intValue();
int n = i;
注:在jdk1.5之前是无自动装箱的,如果要创建一个包装类型整型只能这样 Integer i = new Integer(9)来创建。
写一段简单的代码,然后看看二进制码是什么样子
/**
* 自动装箱和自去拆箱 <br/>
*
* @author yubaba
* @date 2023/7/15 08:53:47
*/
public class AutoPack {
public static void main(String[] args) {
Integer i = 66;
int n = i;
}
}
2.2.1 编译反汇编
先编译,然后用javap -c,反编译查看字节码是什么样子
javap
是Java开发工具包(JDK)中的一个命令行工具,它可以反编译Java类文件并输出类的字节码使用命令 javac AutoPack.java,得到AutoPack.class,如下图:
而想看懂AutoPack.class文件,可以用反编译工具(如jd-gui),也可以用javap命令查看。
javap命令如下:
主要关注两个 -v 和 -c
用命令javap -v AutoPack.class,输下如下:
Classfile /Users/changx/Documents/ws/test/AutoPack.class
Last modified 2023-7-15; size 375 bytes
MD5 checksum 2d1985a02dfdf427efd0659a02bfb263
Compiled from "AutoPack.java"
public class AutoPack
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #5.#14 // java/lang/Object."<init>":()V
#2 = Methodref #15.#16 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
#3 = Methodref #15.#17 // java/lang/Integer.intValue:()I
#4 = Class #18 // AutoPack
#5 = Class #19 // java/lang/Object
#6 = Utf8 <init>
#7 = Utf8 ()V
#8 = Utf8 Code
#9 = Utf8 LineNumberTable
#10 = Utf8 main
#11 = Utf8 ([Ljava/lang/String;)V
#12 = Utf8 SourceFile
#13 = Utf8 AutoPack.java
#14 = NameAndType #6:#7 // "<init>":()V
#15 = Class #20 // java/lang/Integer
#16 = NameAndType #21:#22 // valueOf:(I)Ljava/lang/Integer;
#17 = NameAndType #23:#24 // intValue:()I
#18 = Utf8 AutoPack
#19 = Utf8 java/lang/Object
#20 = Utf8 java/lang/Integer
#21 = Utf8 valueOf
#22 = Utf8 (I)Ljava/lang/Integer;
#23 = Utf8 intValue
#24 = Utf8 ()I
{
public AutoPack();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 7: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=3, args_size=1
0: bipush 66
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: aload_1
7: invokevirtual #3 // Method java/lang/Integer.intValue:()I
10: istore_2
11: return
LineNumberTable:
line 10: 0
line 11: 6
line 12: 11
}
SourceFile: "AutoPack.java"
2.2.2 字节码指令说明
主要看main中的命令,指令说明:
iconst
指令bipush
指令ipush
指令2.2.3 结论
了解了反汇编指命的意思,大概应该就知道源码AutoPack.java在JVM是中如何执行的了。意思如下:
3.1.1 问题与答案
public class Main {
public static void main(String[] args) {
Integer i1 = 66;
Integer i2 = 66;
Integer i3 = 166;
Integer i4 = 166;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}
也许,我们都会说都是false,或者也有人说都是true。而事实结果是
true
false
为什么?不都是调Integer.valueOf()返回Integer对象么?。。
3.1.2 分析
要准确回答正确这个问题,我们看看Integer.valueOf()方法是如何实现的,源码如下:
// jdk 1.8
public final class Integer extends Number implements Comparable<Integer> {
...
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
int h = 127;
String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
...
public static Integer valueOf(int i) {
if (i >= Integer.IntegerCache.low && i <= Integer.IntegerCache.high)
return Integer.IntegerCache.cache[i + (-Integer.IntegerCache.low)];
return new Integer(i);
}
...
}
说明:
3.1.3 结论
public class Main {
public static void main(String[] args) {
Double d1 = 66.0;
Double d2 = 66.0;
Double d3 = 166.0;
Double d4 = 166.0;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}
注:跟3.1思路 一样。其它数据类型也是如此。
public class Main {
public static void main(String[] args) {
Integer a = 2;
Integer b = 4;
Integer c = 6;
Integer d = 6;
Integer e = 166;
Integer f = 166;
Long g = 6L;
Long h = 4L;
System.out.println(c==d); //1
System.out.println(e==f); //2
System.out.println(c==(a+b)); //3
System.out.println(c.equals(a+b));//4
System.out.println(g==(a+b)); //5
System.out.println(g.equals(a+b));//6
System.out.println(g.equals(a+h));//7
}
}
可以自己运行一下看输出结果。