Java基础————理解Integer对象的缓存策略

一个简单的面试题

    public static void main(String[] args) {Integer in1 = 100;Integer in2 = 100;Integer in3 = 200;Integer in4 = 200;System.out.println(in1 == in2);System.out.println(in3 == in4);}

运行结果:

true
false

从自动装箱谈Integer缓存

上述面试题中,in1,in2,in3,in4四个Integer对象都是通过直接赋值int变量完成初始化的,这种赋值方式我们成为自动装箱。

实际上,自动装箱功能只是Java编译器自动帮我们完成了调用Integer.valueOf(int i)的过程,也就是说:

Integer in1 = 100;<-等价于->Integer in1 = Integer.valueOf(100);

了解了这个道理,我们再来回想上面这个问题:为什么一样的调用valueOf方法,却得不到一样的值?

    /*** Returns an {@code Integer} instance representing the specified* {@code int} value.  If a new {@code Integer} instance is not* required, this method should generally be used in preference to* the constructor {@link #Integer(int)}, as this method is likely* to yield significantly better space and time performance by* caching frequently requested values.** This method will always cache values in the range -128 to 127,* inclusive, and may cache other values outside of this range.** @param  i an {@code int} value.* @return an {@code Integer} instance representing {@code i}.* @since  1.5*/public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}

我们看到,在jdk1.5中,加入了valueOf的这个实现过程。在if条件中,如果 i 的值在[IntegerCache.low , IntegerCache.high]之间的话,则取IntegerCache.cache中的一个元素。

IntegerCache缓存类实现如下:

    /*** Cache to support the object identity semantics of autoboxing for values between* -128 and 127 (inclusive) as required by JLS.** The cache is initialized on first usage.  The size of the cache* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.* During VM initialization, java.lang.Integer.IntegerCache.high property* may be set and saved in the private system properties in the* sun.misc.VM class.*/private static class IntegerCache {static final int low = -128;static final int high;static final Integer cache[];static {// high value may be configured by propertyint h = 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);// Maximum array size is Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {// If the property cannot be parsed into an int, ignore it.}}high = h;cache = new Integer[(high - low) + 1];int j = low;for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++);// range [-128, 127] must be interned (JLS7 5.1.7)assert IntegerCache.high >= 127;}private IntegerCache() {}}

缓存类在第一次使用Integer类时被初始化。通过一个for循环初始化了一个拥有256个Integer对象的数组供开发人员使用。它们的范围默认是[-128 , 127],127可以通过修改JVM启动参数-XX:AutoBoxCacheMax=size进行调整。这种方式通过使用相同的对象引用来实现缓存和复用,以此来节省内存和提高性能。

在通过valueOf创建新的Integer对象之前会先在IntegerCache.cache中查找,如果有我们需要的值则直接返回一个指向此对象的引用。否则,才会通过new Integer()方式直接创建Integer对象。

再谈==和equals()

双等于==比较的是对象的内存地址,对于-128到127之间的整数,只要这个引用是通过自动装箱或者显式valueOf()指向一个Integer对象,那么它一定会指向一个IntegerCache.cache数组中的对象,因此物理地址一定相等,而在这个区间以外的整数,因为没有缓存的原因,需要通过new Integer()的方式开辟一块新的物理地址来存储这个对象,因此物理地址一定不同。所以才会有前面面试题中的结果。

Integer.equals()方法,提供了比较两个Integer对象的方法,所以不管是通过new 还是 valueOf方式创建的Integer对象,在实际的业务需求中,往往都是需要比较对象中存储的整数值而不是物理地址,所以,为了避免混淆,应当都使用equals方式来比较两个Integer对象,这样可以减少很多问题。

总结

代码应当是服务于业务的,而不是面试题。这种==比较两个Integer对象的方式应该仅仅在面试题中出现,而不应该是在业务实现中出现,虽然某些时候,可以实现一样的效果,但是代码应该不仅能够实现逻辑的正确性,也应该能够表达一种正确的语义,使他人在阅读你的代码时能够清楚的明白这行代码所要表达的含义。

但并不是说我们不需要理解它的实现过程和需要注意的问题,这道面试题虽然可能不会真正的运用到实际的业务实现中去,但是却提供了一种帮助我们深入了解jdk的手段,使我们更好的了解到API开发人员在帮助我们解决什么问题。所以,不论是工作还是学习,都应该认清我们的需要。

综上,就是对Integer对象缓存策略的剖析和感想,如有疑问,欢迎文末留言。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/558996.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java面试日常总结大杂烩

日常总结大杂烩&#xff1a;一。 取出特定行数的数据1. select* from 表名 limit m,n; 2. select * from 表名 limit [offset,] rows;1. m代表从m1条记录行开始检索&#xff0c;n代表取出n条数据。&#xff08;m可设为0&#xff09;如&#xff1a;select * from表名 limit 6,5…

Eclipse深度患者设置VSCode快捷键

VSCode设置Eclipse中常用的快捷键 将eclipse中一些基本的快捷键输入右侧用户快捷键设置中&#xff1a; // Place your key bindings in this file to overwrite the defaults [{ "key": "alt/", "command": "editor.action.triggerSugges…

Java基础日常总结!!

Java基础日常总结&#xff01;&#xff01;1. Java的字符类型采用的是Unicode编码方案&#xff0c;每个Unicode码占用( )个比特位 在java中一个unicode占2个字节&#xff08;byte&#xff09;.一个字节等于8比特位&#xff08;bit&#xff09;.所以每个Unicode码占用 16 个比特…

NodeJS学习————关于let和const命令的使用理解

let的基本用法 在新的js规范ES6中&#xff0c;新增了let 命令&#xff0c;用来声明变量。用法类似于var&#xff0c;但不同的是所声明的变量&#xff0c;只在let 命令所在的代码块内有效。 { let a 10; var b 10; } //ReferenceError: a is not defined console.log(a …

forward和redirect的区别是什么?

forward和redirect是什么&#xff1f; 是servlet种的两种主要的跳转方式。forward又叫转发&#xff0c;redirect叫做重定向。 区别&#xff1a;&#xff08;本地效应次数&#xff09; 地址栏&#xff0c;数据共享&#xff0c;应用场景&#xff0c;效率&#xff0c;本质&…

MYSQL的索引类型:PRIMARY, INDEX,UNIQUE,FULLTEXT,SPAIAL 有什么区别?各适用于什么场合?

一、MySQL索引类型 MySql常见索引类型有&#xff1a;主键索引、唯一索引、普通索引、全文索引、组合索引 PRIMARY KEY&#xff08;主键索引&#xff09; ALTER TABLE table_name ADD PRIMARY KEY ( column ) UNIQUE(唯一索引) ALTER TABLE table_name ADD UNIQUE (colu…

Servlet入门总结

一、了解Servlet的概念Servlet定义&#xff1a;Servlet是基于Java技术的Web组件&#xff0c;由容器管理并产生动态的内容。Servlet引擎作为WEB服务器的扩展提供支持Servlet的功能。Servlet与客户端通过Servlet容器实现的请求/响应模型进行交互。 注意&#xff1a;Servlet不是从…

MySQL日期类型的处理总结

一、概述 MySQL中的日期类型包括以下5种&#xff1a; 类型大小 (字节)范围格式用途DATE31000-01-01/9999-12-31YYYY-MM-DD日期值TIME3-838:59:59/838:59:59HH:MM:SS时间值或持续时间YEAR11901/2155YYYY年份值DATETIME81000-01-01 00:00:00/9999-12-31 23:59:59YYYY-MM-DD HH:…

详解HTTP协议~~~

详解HTTP协议~~~HTTP 简介HTTP协议是Hyper Text Transfer Protocol&#xff08;超文本传输协议&#xff09;的缩写,是用于从万维网&#xff08;WWW:World Wide Web &#xff09;服务器传输超文本到本地浏览器的传送协议。。HTTP是一个基于TCP/IP通信协议来传递数据&#xff08;…

MyBatis基础知识概述

一、依赖配置 添加依赖即可&#xff0c;jar包或pom依赖&#xff1a; <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>x.x.x</version> </dependency> 二、SqlSessionFactory 2.1 什…

Mybatis Plus————代码生成器

代码生成器 MyBatis Plus是MyBatis的扩展框架&#xff0c;而代码生成器是MP的核心功能之一&#xff0c;另外还有 “条件构造器”和“通用CRUD”等功能。 步骤演示 mp的代码生成器有两种方式自动生成代码&#xff0c;一种是通过main方法来执行程序&#xff0c;另一种是通过maven…

Spring MVC 流程图解析

Spring MVC 流程图解析Spring MVC工作流程图图一图二 SpringMVC工作流程描述DispatcherServlet&#xff0c;HandlerMapping&#xff0c;HandlerExecutionChain&#xff0c;HandlerAdapter&#xff0c;HttpMessageConveter&#xff0c;BindingResult&#xff0c;ModelAndView&am…

Java并发编程实战————可重入内置锁

引言 在《Java Concurrency in Practice》的加锁机制一节中作者提到&#xff1a; Java提供一种内置的锁机制来支持原子性&#xff1a;同步代码块。“重入”意味着获取锁的操作的粒度是“线程”&#xff0c;而不是调用。当某个线程请求一个由其他线程持有的锁时&#xff0c;发出…

java的守护进程与非守护进程

java的守护进程与非守护进程 最近重新研究Java基础知识&#xff0c;发现以前太多知识知识略略带过了&#xff0c;比较说Java的线程机制&#xff0c;在Java中有两类线程&#xff1a; User Thread(用户线程)、Daemon Thread(守护线程) &#xff0c;&#xff08;PS:以前忽略了&a…

双剑合璧————Spring Boot + Mybatis Plus

引言 最近在学习Mybatis Plus的使用&#xff0c;希望通过spring boot快速将mybatis plus整合进来。 对于springboot项目&#xff0c;mybatis plus团队也有自己的启动器 &#xff1a;mybatis-plus-boot-starter。这个依赖内部已经整合了mybatis-spring&#xff0c;也包括非快速…

Java中常用的类,包,接口

Java中常用的类&#xff0c;包&#xff0c;接口包名说明java.lang该包提供了Java编程的基础类&#xff0c;例如 Object、Math、String、StringBuffer、System、Thread等&#xff0c;不使用该包就很难编写Java代码了。java.util该包提供了包含集合框架、遗留的集合类、事件模型、…

Collection框架介绍

Collection&#xff1a;List列表&#xff0c;Set集&#xff0c; Map&#xff1a;Hashtable&#xff0c;HashMap&#xff0c;TreeMapCollection 是单列集合 List 元素是有序的、可重复 有序的 collection&#xff0c;可以对列表中每个元素的插入位置进行精确地控制。 可以根据…

Git初学札记(一)————Git简介与安装

前言 Git是一个开源的分布式版本控制系统&#xff0c;可以有效、高速地处理从很小到非常大的项目版本管理。Git是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源码的版本控制软件。&#xff08;在这里再一次致敬Linus大神&#xff09;特点 分布式相比于集中式的最…

Hashtable、HashMap、TreeMap总结

Hashtable、HashMap、TreeMap总结三者均实现了Map接口&#xff0c;存储的内容是基于key-value的键值对映射&#xff0c;一个映射不能有重复的键&#xff0c;一个键最多只能映射一个值。 &#xff08;元顺初线&#xff09;&#xff08;1&#xff09; 元素特性HashTable中的key、…

Git初学札记(二)————EGit导入远程Git仓库项目(Clone操作)

引言 我们在实际开发项目的时候&#xff0c;难免要使用像Eclipse或者IDEA这样的继承开发工具&#xff0c;除了部分“牙牙学语”的程序员需要手动输入javac去编译程序以外&#xff0c;在实际开发中手动编译并运行项目的“猿族”应该是已经绝种了。 我个人认为&#xff0c;使用gi…