ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Java八股篇 —— int 和 Integer

Java八股篇 —— int 和 Integer int 和 Integerint 是基本数据类型Integer 是一种引用类型。基本数据类型是 Java 中最基本的数据类型是预定义的不需要实例化这意味着不需要为对象进行内存分配。而 Integer 必须为对象分配内存。性能方面基本数据类型操作比引用类型快。如果说「基本类型不需要内存分配」这句话那么只对了一半int是要占内存的64 位 HotSpot 上就是 4 字节 —— 只是它跟着栈帧一起走它真正省掉的是堆上的对象分配不 new 对象、不交 12 字节的对象头、不用 GC 管GCGarbage Collector垃圾回收就是 JVM 自动帮我们找不再使用的对象释放它们占用的堆内存不用程序员手动写代码释放内存。所以更准确的说法是int不需要为对象分配内存Integer需要。下面三张图把「内存分配」这件事拆开看。一、内存分配是什么栈上放值还是堆上盖房要点栈Stack线程私有方法一调用就分配、一返回就整体弹出。变量名直接绑定在一块内存上。堆Heap所有线程共享new出来的对象都住这儿生命周期不归方法管只能等 GC 回收。int a 10;—— 那 4 个字节里存的就是10本身仅此而已。Integer b 10;—— 栈上只有 4 个字节存的是一个地址真正的对象在堆上由12 字节对象头 4 字节 int 数据 16 字节组成。所谓「必须为对象分配内存」指的就是后面这步先在堆上把房子盖好再把门牌号写回栈上的变量里。二、Integer b 10;背后到底发生了什么自动装箱和拆箱Integer 是 int 的包装类可以实现自动装箱和拆箱自动装箱把 int 赋值给 Integer 引用变量Integer b10 只中10 就是 int自动拆箱把Integer对象直接赋值给int变量javac会在编译期把它改写成Integer.valueOf(10)—— 这就是自动装箱。valueOf先查[-128, 127]是否命中缓存池IntegerCache命中就直接返回现成对象0 次分配超出范围才new。反向的int x b;会被改写成b.intValue()也就是拆箱b为null时会抛NullPointerException。所以Integer a 127, b 127; a b是true而128却是false——比的是地址不是数值。比较包装类的值请一律用equals()。三、那为什么还要有 Integer因为 Java 里有一半的世界只认对象泛型与集合ListInteger可以Listint编译不过表达「没有值」数据库可空列、查不到的结果只有引用类型能写nullint只能拿 0 冒充要放进Object的位置Object[]、反射、JSON 序列化、Map的 key基本类型递不进去需要类型自带的工具Integer.parseInt、Integer.MAX_VALUE、Integer.toBinaryString要参与多态Number让Integer/Long/Double有了共同父类基本类型没有继承关系。代价也必须认内存约 5 倍、GC 多扫一堆对象、CPU 缓存不友好、和拆箱 NPE 两个坑。小林 Coding 中的资料问题Q1int 和 Integer 区别是什么基本类型和引用类型自动装箱和自动拆箱空指针异常int 变量默认值为 0Integer 作为引用类型默认值为 null如果对一个值为 null 的 Integer 执行自动拆箱操作就会抛出空指针异常因为 null 无法被拆箱为基本类型Q2为什么要保留 int 类型包装类是引用类型对象的引用和对象本身是分开存储的而对于基本类型数据变量对应的内存块直接存储数据本身。因此基本类型数据在读写效率方面要比包装类高效。除此之外在 64 位 JVM 上在开启引用压缩的情况下一个 Integer 对象占用 16 个字节的内存空间可以看前面那个堆栈示意图而一个 int 类型数据只占用 4 字节的内存空间前者对空间的占用是后者的 4 倍。也就是说不管是读写效率还是存储效率基本类型都比包装类高效。Q3说一下 integer 的缓存Java 的 Integer 类内部实现了一个静态缓存池用于存储特定范围内的整数值对应的 Integer 对象。默认情况下这个范围是 - 128 至 127。当通过 Integer.valueOf (int) 方法创建一个在这个范围内的整数对象时并不会每次都生成新的对象实例而是复用缓存中的现有对象会直接从内存中取出不需要新建一个对象。
返回列表