Java一直标榜自己是纯面向对象的语言,为所有的值类型都提供相应的引用类型是很聪明的。例如:int类型对应Integer,前者是一个值,后者是一个引用。为了方便两者之间的转换,还有一个功能叫做“自动拆箱”,把原本清晰的概念打乱了。一门优秀的语言应该是语法简单、语义单一、清晰。本文讨论其乱七八糟的概念(我看不懂),直奔主题——通过阅读JVM代码来判断发生了什么。解释class文件JVM是一个栈虚拟机,它提供的指令都是围绕栈进行的。使用javap-c查看类文件中的JVM指令。下面的代码,左边的Java代码是它右边的JVM代码。查看每条指令执行后栈的变化:bipush直接将数字20压入栈invokestatic调用静态方法在堆中构造一个对象,然后将对象的地址压入栈astore_1记录内存Integer对象的地址到一个内部变量中(JVM在堆中维护了一个很大的变量表,表示变量名和变量值的关系,可以想象成一个HashMap。)此时,代码Integer=20被执行。接下来,bipush将10压入堆栈asotre2并将变量b与堆栈中的10相关联(将其放入变量表中)。总结:value变量指向的内容(值)放在栈中,访问时可以直接操作栈引用变量指向的内容(对象)放在堆中。访问时,先将变量加载到栈中(通过aload_1指令,例子中没有出现),再进行操作。访问wrapper对象时发生的事情Integerc=null;Integerd=10;inte=c+d;JVM代码是(1)wrapper对象的空指针问题aconst_null将一个空指针压入栈中,astore_1将变量放在栈顶入栈到变量表中,所以此时a为null,所以会出现空指针错误。(2)封装对象的计算方法8-16是计算两个数相加,aload_1将变量表中的变量压入栈中,invokervirtual指令将对象转成int压回堆;第12行和第13行的逻辑是相同的。第16行执行整数加法。因为计算结果是int类型,所以最终通过isotre_3放入变量表中。自己分析如果最后一行代码写成Integere=c+d;,JVM代码就变成自己分析了。总结Java的包装数据类型非常糟糕,这就是它为“肤浅的面向对象”付出的代价。威压之势,如雷霆万钧,骇人听闻。【本文为专栏作家“行森”原创文章,转载请联系作者获得授权】点此阅读更多本作者好文