Java中基本数据类型都有相对应的包装类

什么是装箱?什么是拆箱?

在Java SE5之前,Integer是这样初始化的

Integer i = new Integer(10);

而在从Java SE5开始就提供了自动装箱的特性,如果要生成一个数值为10的Integer对象,只需要这样就可以了:

Integer i = 10;

这个过程中会自动根据数值创建对应的 Integer对象,这就是装箱。

关于boolean占用几个字节,请参考:https://www.jianshu.com/p/2f663dc820d0

public static void main(String[] args) {
Integer i = 10; //装箱
int i1 = i;   //拆箱
}

装箱:自动将基本数据类型转换为包装器类型

拆箱:自动将包装器类型转换为基本数据类型

有了基本数据类型,为什么还需要包装类?

  Java是面向对象的,而基本数据类型和对象完全不搭边。只能单纯使用数值时节省内存空间但是无法进行相关函数操作

  包装类型为其添加了属性和方法,丰富了基本类型的操作,但有占用更多的内存空间

  为了相互转换比较方便,所以通过包装基本数据类型就可以变成一个对象

PS:

  往集合里保存数据的时候,假如add一个int类型,都是自动装箱成Integer的,因为ArrayList、HashMap等,保存的都是Object

public static void main(String[] args) {
int i = 1;
List list = new ArrayList();
list.add(i);
}

我们通过javap反编译查看:

public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: new #2 // class java/util/ArrayList
5: dup
6: invokespecial #3 // Method java/util/ArrayList."<init>":()V
9: astore_2
10: aload_2
11: iload_1
12: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
15: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
20: pop
21: return
}

第12行,通过调用Integer.valueOf(),实现把int自动装箱转换为Integer,证实了上面的说话

自动装箱、拆箱如何实现:

public static void main(String[] args) {
Integer i = 10;
int i1 = i;
}
public class com.it.Test {
public com.it.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: bipush 10
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
}

反编译之后很容易看出来,通过Integer.valueOf(int)实现自动装箱,通过Integer.intValue()实现自动拆箱

其他基本数据类型,也都是相似的过程,例如char

public static void main(String[] args) {
Character character = 'a';
char c = character;
}
public static void main(java.lang.String[]);
Code:
0: bipush 97
2: invokestatic #2 // Method java/lang/Character.valueOf:(C)Ljava/lang/Character;
5: astore_1
6: aload_1
7: invokevirtual #3 // Method java/lang/Character.charValue:()C
10: istore_2
11: return

概括自动装箱、拆箱实现:

  装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的 xxxValue方法实现的(xxx代表对应的基本数据类型)

相关面试题:

1、Integer相关代码的输出结果是什么?

public static void main(String[] args) {

	Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200; System.out.println(i1==i2);
System.out.println(i3==i4);
}

输出结果:

true
false

  结果可能跟你想象的不同,i1和i2指向的是同一个对象,而i3和i4指向的是不同的对象。此时只需一看源码便知究竟,下面这段代码是

Integer的valueOf方法的具体实现:

public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}

  在通过valueOf方法创建Integer对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则

创建一个新的Integer对象。

  上面的代码中i1和i2的数值为100,因此会直接从cache中取已经存在的对象,所以i1和i2指向的是同一个对象,而i3和i4则是分别指向不同

的对象。

2.Double相关代码的输出结果是什么?

public static void main(String[] args) {

	Double i1 = 100.0;
Double i2 = 100.0;
Double i3 = 200.0;
Double i4 = 200.0; System.out.println(i1==i2);
System.out.println(i3==i4);
}
false
false

也许有人会认为跟上面一道题目的输出结果相同,但是事实上却不是。

Double.valueOf()源码如下:

public static Double valueOf(double d) {
return new Double(d);
}

Double.valueOf()与Integer.valueOf()为什么实现不同?

原因是在某个范围内的整型数值的个数是有限的,而浮点数却不是。

PS:Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。

  Double、Float的valueOf方法的实现是类似的。

3.Boolean相关代码输出结果是什么:

public static void main(String[] args) {

	Boolean i1 = false;
Boolean i2 = false;
Boolean i3 = true;
Boolean i4 = true; System.out.println(i1==i2);
System.out.println(i3==i4);
}

输出结果:

true
true

Boolean.valueOf()源码如下:

public static final Boolean TRUE = new Boolean(true);

public static final Boolean FALSE = new Boolean(false);

public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}

4.谈谈Integer i = new Integer(xxx)和Integer i =xxx;的区别

当然,这个题目属于比较宽泛类型的。但是要点一定要答上,我总结一下主要有以下这两点区别:

  1)第一种方式不会触发自动装箱的过程;而第二种方式会触发;

  2)在执行效率和资源占用上的区别。第二种方式的执行效率和资源占用在一般性情况下要优于第一种情况(注意这并不是绝对的)。

5.下面程序的输出结果是什么?

public static void main(String[] args) {
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
Long h = 2L; System.out.println(c==d);
System.out.println(e==f);
System.out.println(c==(a+b));
System.out.println(c.equals(a+b));
System.out.println(g==(a+b));
System.out.println(g.equals(a+b));
System.out.println(g.equals(a+h));
}

  先别看输出结果,自己想一下这段代码的输出结果是什么。

  这里面需要注意的是:当 "=="运算符的两个操作数都是包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数

是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。

  另外,对于包装器类型,equals方法并不会进行类型转换。明白了这2点之后,上面的输出结果便一目了然:

输出结果:

true
false
true
true
true
false
true

1和2:结果应该没疑问

3:由于a+b包含了算术运算,因此会触发自动拆箱过程(会调用intValue方法),因此它们比较的是数值是否相等。

4:而对于c.equals(a+b)会先触发自动拆箱过程,再触发自动装箱过程,也就是说a+b,会先各自调用intValue方法,得到了加法运算后的

数值之后,便调用Integer.valueOf方法,再进行equals比较。

5:g==(a+b),a+b会先触发自动拆箱过程,比较的是数值是否相等,Integer会自动转为Long,所以结果是true

6:g.equals(a+b),我们可以反编译查看:

public static void main(java.lang.String[]);
Code:
0: iconst_1
1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: astore_1
5: iconst_2
6: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
9: astore_2
10: ldc2_w #3 // long 3l
13: invokestatic #5 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
16: astore_3
17: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
20: aload_3
21: aload_1
22: invokevirtual #7 // Method java/lang/Integer.intValue:()I
25: aload_2
26: invokevirtual #7 // Method java/lang/Integer.intValue:()I
29: iadd
30: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
33: invokevirtual #8 // Method java/lang/Long.equals:(Ljava/lang/Object;)Z
36: invokevirtual #9 // Method java/io/PrintStream.println:(Z)V
39: return

过程: 

1、Integer a = 1;    //通过Integer.valueOf(int)进行自动装箱
2、Integer b = 2; //通过Integer.valueOf(int)进行自动装箱
3、Long g = 3L; //通过Long.valueOf(long)进行自动装箱
4、System.out.println(g.equals(a+b));
//a+b,a和b首先通过Integer.intValue()转换为int,然后执行+,也就是iadd指令
//然后遇到equals(),通过Integer.valueOf(int)将结果转换为Integer
//最后Long.equals(Integer),两种类型不同,得到false
//返回输出

7:我们已经能够想象g.equals(a+h)的字节码了,最后是Long和Long通过equals比较,得到true

内容转载自:深入剖析Java中的装箱和拆箱,有修改,添加内容

Java基础(十四)--装箱、拆箱详解的更多相关文章

  1. Java 基础巩固:装箱拆箱 你真的熟悉吗

    先考两道题: Integer a1 = 300; Integer a2 =300; System.out.print(a1 == a2); Integer b1 = 1; Integer b2 = 1 ...

  2. Java中的自动装箱拆箱

    Java中的自动装箱拆箱 一.自动装箱与自动拆箱 自动装箱就是将基本数据类型转换为包装类类型,自动拆箱就是将包装类类型转换为基本数据类型. 1 // 自动装箱 2 Integer total = 90 ...

  3. “全栈2019”Java第五十四章:多态详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  4. Java基础-反射(reflect)技术详解

    Java基础-反射(reflect)技术详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.类加载器 1>.JVM 类加载机制  如下图所示,JVM类加载机制分为五个部分 ...

  5. Java基础-变量的定义以及作用域详解

    Java基础-变量的定义以及作用域详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.字面量 常量(字面量)表示不能改变的数值(程序中直接出现的值).字面量有时也称为直接量,包 ...

  6. Java基础-DBCP连接池(BasicDataSource类)详解

    Java基础-DBCP连接池(BasicDataSource类)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程 ...

  7. “全栈2019”Java第二十九章:数组详解(中篇)

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  8. Java基础13:反射与注解详解

    Java基础13:反射与注解详解 什么是反射? 反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性. Orac ...

  9. java的装箱和拆箱详解

    ========================================================================================= 在我看来,学习jav ...

随机推荐

  1. lucene 索引文件大小分布_tim

    Hi, I have index ~31G where27% of the index size is .fdt files (8.5G)20% - .fdx files (6.2G)37% - .f ...

  2. java虚拟机内存区域理解

    java虚拟机有的区域随着虚拟机进程的启动而存在, 有的区域依赖用户线程的启动和结束而建立和销毁. 程序计数器:为了线程切换后能恢复到正确的执行位置,每个线程都有一个独立的程序计数器.(针对java方 ...

  3. BZOJ_2819_Nim_树状数组维护出栈入栈序

    BZOJ_2819_Nim_树状数组维护出栈入栈序 Description 著名游戏设计师vfleaking,最近迷上了Nim.普通的Nim游戏为:两个人进行游戏,N堆石子,每回合可以取其中某一堆的任 ...

  4. linux文件名乱码时删除或改名的方式(转载)

    转自:http://www.linuxsa.cn/when-linux-file-name-topsy-turvy-deleted-or-renamed.html linux文件名乱码时删除或改名的方 ...

  5. PHP tripos()函数使用需要注意的问题

    tripos() 函数返回字符串在另一个字符串中第一次出现的位置.这在PHP字符串匹配与替换的时候常用到,但是很多时候我们总感觉当查找的字符串在源字符串的开头的时候总会不好使. 原来stripos() ...

  6. js字符串去除连续或全部重复字符

    js字符串去除连续重复字符 ()和\number 配合使用表示重复正则第number个括号内匹配到的内容,如:(\d)\1表示重复第一个匹配块(\d)即等价于如果(\d)匹配到a,则表达式为aa 相应 ...

  7. vue中使用element写点击input内部标签(使用模态框传值)

    首先附上源码地址 https://files.cnblogs.com/files/maruihua/vue-tagsinput-master.zip 这个是我修改后的代码.取消了部分功能,添加的一些功 ...

  8. 【爬坑系列】之docker的overlay网络配置(未完,待续)

    理论知识储备: 想了解vxlan网络的知识:https://www.cnblogs.com/shuiguizi/p/10923841.html 想了解docker网络的原理知识:https://www ...

  9. 第四篇(那些JAVA程序BUG中的常见单词)

    xxx cannot be resolved to a variable xxx无法解析为变量 resolve 解析

  10. JS 数据类型入门与typeof操作符

    标准的数据类型划分: 基本类型: number(数字).string(字符串).undefined.boolean(布尔值).null(空对象) //空对象与非空对象,最大的区别就是不能进行属性操作 ...