一分钟理解Java包装类型

开发 开发工具 后端
Java 一直标榜自己是一个纯粹的面向对象语言,自作聪明的为所有的值类型都提供相应的引用类型。本文我们直接进入正题——通过阅读 JVM code 判断究竟发生了什么。

Java 一直标榜自己是一个纯粹的面向对象语言,自作聪明的为所有的值类型都提供相应的引用类型。

比如:int 类型对应的有 Integer,前者是一个值,后者是一个引用。为了方便二者的转换又一个叫“自动拆装箱”的特性,把本来清晰的概念搞的乱七八糟。

一个优秀的语言应该语法简单,语义单一、清晰。

本文讨论它这些乌七八糟的概念(我也搞不懂),直接进入正题——通过阅读 JVM code 判断究竟发生了什么。

解读 class 文件

JVM 是一个栈式虚拟机,它提供的指令都是围绕着栈进行的。通过javap -c <className>查看一个 class 文件中的 JVM 指令。

如下代码,左边是 Java 代码右边是它的 JVM code。

解读 class 文件

看一下每条指令执行完后栈的变化:

bipush 把数字 20 直接 push 到栈

invokestatic 调用一个静态方法在堆中构造一个对象,然后把对象的地址压入到栈

astore_1 把 Integer 对象的内存地址记录到一个内部变量中(JVM 在堆中维护了一张大的变量表,代表变量名和变量值的关系,可以想象成 HashMap。)

至此,Integer = 20 这句代码执行完毕。紧接着看,bipush 把 10 压入栈

asotre2 把变量 b 和栈中的 10 做关联(放到变量表中)

总结:

  • 值变量所指向的内容(值)是放在栈中的,访问时直接操作栈
  • 引用变量所指向的内容(对象)是放在堆中的,访问时先把变量载入到栈(通过aload_1 指令,例子中没有出现),再操作。

访问包装对象时发生了什么

  1. Integer c = null
  2. Integer d = 10
  3. int e = c + d; 

JVM code 为

(1) 包装对象的空指针问题

aconst_null 把一个空指针压入栈,astore_1 把栈顶的变量放入到变量表中,所以此时 a 是 null,所以会出现空指针错误。

(2) 包装对象的计算方法

8-16 是计算两数相加,aload_1 把变量表中的变量压入栈,invokervirtual 指令把对象转换成 int 重新入栈;12、13 行的逻辑也是如此。 16 行执行整数相加。

因为计算结果是 int 类型,所以最后通过 isotre_3 放到变量表。

自己分析

如果代码的最后一行写作Integer e = c + d;,JVM code 会变成

自己动手分析一下看看吧。

总结

Java 的包装数据类型非常蹩脚,这是它为了追求“表面的面向对象”而付出的代价。装逼之势如雷霆万钧,可怕。

【本文是51CTO专栏作者“邢森”的原创文章,转载请联系作者本人获取授权】

戳这里,看该作者更多好文

责任编辑:赵宁宁 来源: 51CTO专栏
相关推荐

2018-07-31 16:10:51

Redo Undo数据库数据

2017-02-21 13:00:27

LoadAverage负载Load

2018-06-26 05:23:19

线程安全函数代码

2017-03-30 19:28:26

HBase分布式数据

2018-07-31 15:05:51

Java公平锁线程

2018-06-26 10:52:45

2018-06-28 14:00:01

分布式集群架构

2020-07-09 07:37:06

数据库Redis工具

2020-07-17 07:44:25

云计算边缘计算IT

2016-09-12 17:28:45

云存储应用软件存储设备

2017-07-06 08:12:02

索引查询SQL

2020-05-21 19:46:19

区块链数字货币比特币

2022-07-18 06:16:07

单点登录系统

2018-03-27 09:28:33

缓存策略系统

2016-12-16 11:05:00

分布式互斥线程

2015-11-12 10:32:40

GitHub控制系统分布式

2021-08-06 08:50:45

加密货币比特币区块链

2011-02-21 17:48:35

vsFTPd

2016-12-21 15:08:14

数据库垂直拆分

2009-12-02 17:21:19

Cisco路由器配置
点赞
收藏

51CTO技术栈公众号