在 Java 的世界中,对象是一等公民,但 Java 也还是做出了妥协,出于对性能的考虑而保留了 8 种基础数据类型。



本文基于 JDK1.8



但是在某些场景下,无法直接使用基本数据类型,所以还是需要使用对象,Java 的包装类就是这样出现的。

自动装箱和拆箱



看下面的代码:

ArrayList list = new ArrayList();int i = 1;list.add(i); // 装箱;



Java 编译器会自动把基本数据类型转成对象,这个称之为装箱。 到底是怎么做到的呢?看下面的字节码:

// ...12: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;15: invokevirtual #10 // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z// ...



简单解释一下 invokestatic 和 invokevirtual,这两个都是 JVM 的指令,前者表示调用 Java 的

静态方法,后者表示调用对象方法。



invokestatic 调用了 Integer.valueOf() 方法,所以装箱实际上就是调用了 Integer.valueOf() 方法。



拆箱也很简单,看下面的代码:

Integer i = 1;int i2 = 1; // 拆箱;



拆箱的字节码如下:

// ... 7: invokevirtual #2 // Method java/lang/Integer.intValue:()I // ...



同理,拆箱实际调用的是 Integer 对象方法 i.intValue()。



从上文可以看出,Java 中基本类型的装箱和拆箱实际上是编译器提供的语法糖,是在编译器层面进行处理的,编译器会将装箱和拆箱编译成调用方法的字节码。在虚拟机层,通过调用方法来实现包装类的装箱和拆箱。



Byte,Short,Long,Float,Double,Boolean,Character 与 Integer 类似。

但是需要注意,还有一个特殊的包装类 Void。 Void 是 void 的包装类,Void 不能被继承,也不能被实例化,仅仅就是一个占位符。



如果一个方法使用 void 修饰,说明方法没有返回值,如果使用 Void 修饰,则该方法只能返回 null。

public Void nullFunc() { return null; // 返回其他值会编译不通过}



Void 常用于反射中,判断一个方法的返回值是不是 void。

for (Method method : VoidDemo.class.getMethods()) { if (method.getReturnType().equals(Void.TYPE)) { // ... }}



包装类的缓存



看下面的代码:

Integer i1 = 200;Integer i2 = 200;System.out.println(i2 == i1); // falseInteger i3 = new Integer(100);Integer i4 = new Integer(100);System.out.println(i3 == i4); // falseInteger i5 = 100;Integer i6 = 100;System.out.println(i5 == i6); // true



上面的代码应该算是一道经典的面试题了。通过上文可知,装箱操作使用的是 Integer.valueOf() 方法,源码如下:

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



关键实现在 IntegerCache 中,在某个范围内的数值可以直接使用已经创建好的对象。IntegerCache 是一个静态内部类,而且不能实例化,仅仅用来缓存 Integer 对象:

private static class IntegerCache { static final int low = -128; // 缓存对象的最小值,不能配置 static final int high; static final Integer cache[]; static { int h = 127; // 缓存对象的最大值可以配置,但是不能超过 Integer的最大值,不能小于 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) { } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); assert IntegerCache.high >= 127; } private IntegerCache() {}}



缓存对象的默认大小范围是 -128 ~ 127,正数范围可以根据自己的需要进行调整,负数最小就是 -128,不可以调整。如果不在这个范围内,就会创建新的对象。



上面代码的结果就很清晰了,第一个结果为 false 是因为 200 超出了默认的缓存范围,因此会创建新的对象。第二个结果为 false 是因为直接使用 new 来创建对象,而没有使用缓存对象。第三个结果为 true 是因为刚好在缓存的范围内。



所以在使用 Integer 等包装类生成对象时,不要使用 new 去新建对象,而应该尽可能使用缓存的对象,而且比较两个 Integer 对象时不要使用 ==,而应该使用 equals。



其他的包装类的实现基本类似,只是在对象缓存上的实现有些不同: Byte 的范围刚好是 -128~127,所以都可以直接从缓存中获取对象。 Short 缓存范围也是 -128 ~ 127,而且不可以调整。 Long 的实现与 Short 一致。 Character 因为没有负数,所以缓存范围是 0 ~ 127,也不可以调整范围。 Boolean 的值只有 true 和 false,在类加载的时候直接创建好。 Float,Double 则没有缓存机制,因为是浮点数,可以表示无穷无尽的数,缓存的意义不大。



小心空指针



此外还需要注意的一点就是,使用包装类生成的是对象,是对象就有可能出现空指针异常,在代码中需要进行处理。

Integer integer = null;int i = integer; // NPE



java为什么要设计包装类_Java 为什么需要包装类相关推荐

  1. java常用类的特征_Java常用类-包装类

    一. 包装类的使用 java提供了8种基本数据类型对应的包装类,使得基本数据类型的变量具有类的特征 需要掌握的:基本数据类型.包装类.String三者之间的相互转换 基本数据类型 <------ ...

  2. java高级课程设计报告书_java高级课程设计报告模板

    java高级课程设计报告模板 Java 高级课程设计报告 课程设计名称:Java高级课程设计 学 期:13-14-1 班 级:计网1231班 姓 名:黄磊 指 导 老 师:刘志生.白党强 一.课程设计 ...

  3. java游戏课程设计报告_java课程设计报告游戏_相关文章专题_写写帮文库

    时间:2019-05-14 00:00:44 作者:admin 课 程 设 计 课程名称 Java语言课程设计 题目名称 人事管理系统的设计与实现 学生学院 应用数学学院 专业班级 学 号 学生姓名 ...

  4. java主窗体设计代码_java窗体设计+GUI经典代码全放送

    [实例简介] java窗体设计经典代码,手把手叫你如何设计java窗体,编写应用程序. [实例截图] [核心代码] 57641e3b-d82c-4f28-bb29-35f951c1158d └── j ...

  5. java 包装类_Java中的包装类

    Java中哪些需要包装类 它们将原始数据类型转换为对象.如果我们希望修改传递给方法的参数,则需要对象(因为基元类型是按值传递的). java.util包中的类只处理对象,因此在这种情况下包装类也有帮助 ...

  6. java万年历的设计总结_java万年历设计报告

    内容来自用户:Van2830 JAVA大作业 目录 作业要求2项目概述2具体功能介绍3设计与实现3作业要求:62616964757a686964616fe59b9ee7ad94313334336464 ...

  7. java贪吃蛇设计流程_JAVA版贪食蛇(贪吃蛇)游戏的设计与实现(含录像)

    JAVA版贪食蛇(贪吃蛇)游戏的设计与实现(含录像)(任务书,开题报告,外文翻译,毕业论文12000字,程序代码,MySQL数据库,答辩PPT,答辩视频录像) 摘要 "贪食蛇"游戏 ...

  8. java char 包装类_Java 基本类型包装类

    Java基本类型包装类: 基本数据类型    基本类型包装类 byte               Byte short              Short int                 ...

  9. java qq课程设计报告_JAVA课程设计报告语音QQ仿真

    JAVA课程设计报告语音QQ仿真 <Java 程序设计>课程设计报告 题 目: 语音 QQ 仿真 学 院:计算机科学与工程 专 业:物联网工程 学生姓名: xx 学 号: 13003701 ...

  10. java开发微信设计论文_java+mysql微信的烘焙公众号的设计与实现

    摘要随着社会的发展人们的生活压力逐渐变大,人们日常的生活节奏也急剧加速,由此导致时间的缺少,人与人之间面对面交流的机会也越来越少.然而人类是一种群居生物,随时渴望有着他人的陪伴,这种陪伴不仅仅是物质上 ...

最新文章

  1. matplotlib中plot的颜色
  2. java怎么获取服务器文件夹,java获取远程服务器的文件夹
  3. 【收藏】spring boot+websocket+echarts 后台推送数据用echarts展示
  4. Spring和JSF集成:国际化和本地化
  5. [react] React中怎么检验props?
  6. VC6.0创建文件夹
  7. MooTools 1.4 源码分析 - (关于Core、Type等模块分析)
  8. MyEclipse7.0及JDK1.6.0的安装及配置过程(修改)
  9. freemarker转PDF,分页,页眉和页脚,画图
  10. 小程序毕设作品之微信积分商城小程序毕业设计成品(6)开题答辩PPT
  11. Turtle库是Python语言中一个很流行的绘制图像的函数库
  12. 51单片机数码管闪烁c语言,AT89C51单片机数码管闪烁问题怎么解决
  13. Selenium电脑上怎么下载-Selenium下载和安装图文教程[超详细]
  14. 2022小米红米手机最新最全MIUI刷机教程内测版到稳定版 不清除数据(线刷、卡刷)
  15. 范围查询-sql语句
  16. 基于Flink建设流批一体实时数仓
  17. 征途LINUX服务端脚本,征途【改版教程】-版本内脚本文件-转载于-喜欢玩网游单机站...
  18. 如何做到高效沟通和高效沟通的好处
  19. 制作商品详情页面案例
  20. 安装hadoop 问题记录

热门文章

  1. Python Bug: TypeError: a bytes-like object is required, not ‘str
  2. Light Field 光场以及Matlab光场工具包(LightField ToolBox)的使用说明
  3. Python 之pdb调试
  4. pyinstaller 打包错误集锦
  5. luogu P3193 [HNOI2008]GT考试
  6. 洛谷 2017.7月赛解题报告
  7. 61单片机程序下载一闪而过,下载完成之后没有看到实验现象。
  8. 不同版本操作系统和数据库的之间链接,和操作
  9. Ajax与jQuery异步加载数据
  10. 软件工程师与码农的区别