zoukankan      html  css  js  c++  java
  • 一起谈.NET技术,C#之int挑战Java之Integer 狼人:

      本文涉及到一些JVM原理和Java的字节码指令,推荐感兴趣的读者阅读一本有关JVM的经典书籍《深入Java虚拟机(第2版)》,将它与我在《.NET 4.0面向对象编程漫谈》中介绍的CLR原理与IL汇编指令作个对比,相信读者会有一定的启发。而仔细对比两个类似事物的异同,是很有效的学习方法之一。

      今后我还将在个人博客上放出其他的文章,希望能帮助书的读者开拓视野,启发思考,大家一起探讨技术的奥秘。

      本文所述之内容仅代表个人之理解,任何疏漏及错误请直接回贴指出。

      1 奇特的程序输出

      前段时间,一个学生给我看了一段“非常诡异”的Java代码:

    public class TestInteger {
    public static void main(String[] args){
    Integer v1
    =100;
    Integer v2
    =100;
    System.out.println(v1
    ==v2); //输出:true
    Integer w1=200;
    Integer w2
    =200;
    System.out.println(w1
    ==w2); //输出:false
    }
    }

      让这个学生最困惑的是,为什么这些如此相似的代码会有这样令人意外的输出?

      我平时多使用C#,Java用得不多,初看到这段代码的输出,我也同样非常奇怪:怎么会这样呢?100和200这两个整型数值对Integer这个类有本质上的差别吗?

      为了弄明白出现上述现象的底层原因,我使用javap工具反汇编了Java编译器生成的.class文件:

    1

      通过仔细阅读Java编译器生的字节码,我发现以下给Integer变量赋值的语句:

      Integer v1=100;

      实际上调用的是Integer.valueOf方法。

      而完成两个Integer变量比较的以下语句:

      System.Console.WriteLine(v1 == v2);

      实际生成的是if_acmpne指令。其中的a代表“address”,cmp代表“Compare”,ne代表“not equal”。

      这条指令的含义是:比较Java方法栈中的两个操作数(即v1与v2),看看它们是不是指向堆中的同一个对象。

      当给v1和v2赋值100时,它们将引用同一个Integer对象。

      那为什么当值改为200时,w1和w2就“翻脸了”,分别引用不同的Integer对象?

      秘密就在于Integer.valueOf方法。幸运的是,Java的类库是开源的,所以我们可以毫不费力地看到相关的源代码:

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

      一切真相大白,原来Integer在内部使用了一个私有的静态类IntegerCache,此类内部封装了一个Integer对象的cache数组来缓存Integer对象,其代码如下:

    private static class IntegerCache {
    static final Integer cache[];
    //……
    }

      再仔细看看IntegerCache内部的代码,会看到它使用静态初始化块在cache数组中保存了[-128,127]区间内的一共256个Integer对象。

      当给Integer变量直接赋整数值时,如果这个数值位于[-128,127]内,JVM(Java Virtual Machine)就直接使用cache中缓存的Integer对象,否则,JVM会重新创建一个Integer对象。

      一切真相大白。 

  • 相关阅读:
    运用Scapy编写类似于Nmap的端口扫描脚本
    centos7 下安装arping工具
    Redis protected-mode属性解读
    centos7编写自己的服务,运行systemctl后卡住了(即shell阻塞了)
    logback日志增加行号
    nginx隐藏版本号server_tokens
    关于数据库Oracle表字段为NVARCHAR2 与Mybatis Generator运用问题
    浅析MySQL的分区(Partition)功能
    浅析PostgreSQL序列(SEQUENCE)、常用序列操作、数据迁移后更新序列流程
    浅析mybatis里的缓存机制
  • 原文地址:https://www.cnblogs.com/waw/p/2163198.html
Copyright © 2011-2022 走看看