Java学习点滴——Integer缓存
前言
一切从下面这段代码开始
public static void test(String[] agrs){
Integer a = 1;
Integer b = 2;
System.out.println("a=" + a + ", b=" + b);
swap( a, b );
System.out.println("a=" + a + ", b=" + b);
}
public static void swap( Integer a, Integer b ){
// 实现它
}
过程
因为Java中的方法只有值传递,所以无法使用下面的方式来完成交换。
public static void swap( Integer a, Integer b ){
Integer tmp = a;
a = b;
b = tmp;
}
因为Integer没有提供直接修改值的方法,所以能想到的就是用反射机制去修改Integer对象持有的值。于是就有了下面的代码
public static void swap( Integer a, Integer b ){
try {
Integer tmp = new Integer(a);
Field fieldA = a.getClass().getDeclaredField("value");
fieldA.setAccessible(true);
fieldA.set(a, b);
Field fieldB = b.getClass().getDeclaredField("value");
fieldB.setAccessible(true);
fieldB.set(b, tmp);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
执行后发现a和b引用对象的值确实交换了。
但是在main()的最后加上这段代码,会发现输出是c=2!!
Integer c = 1;
System.out.println("c=" + c);
Integer缓存
查看字节码可以发现Integer a = 1;实际是通过Integer.valueOf()获取的Integer对象。
Integer.valueOf()源码如下
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
我们发现当i在[IntegerCache.low,IntegerCache.high]区间内时,总是返回cache中的对象引用。
low不可配置,默认为-128;high可配置,默认为127。
由此就可以知道,因为a和b引用的是cache中的对象,swap()后,cache中对象的值和其在数组中的下标已经不对应了,所以c引用的对象的实际值是2。
为了避免交换影响到Integer的缓存,我们必须使用new来实例化a和b引用的对象。
结语
Java似乎就是有意不让程序员去修改对象内存的,只能改改引用的对象,像String的替换、追加等操作,都是返回一个新实例化的对象,而不是在原对象的内存中修改。
Java学习点滴——Integer缓存的更多相关文章
- Java学习点滴——初识Java
基于<Java编程思想>第四版 前言 "程序就是算法加数据结构",而算法就是控制语句加操作符,编写一个程序就是使用控制语句加操作符去操作数据结构,因此我从Java的控制 ...
- java封装数据类型——Integer 缓存策略验证
上一篇学习 Integer 类型源码,知道了它使用缓存策略,默认对 [-128, 127] 范围的对象进行类加载时自动创建缓存. Integer 源码学习:https://www.cnblogs.co ...
- Java学习点滴——泛型
基于<Java编程思想>第四版 前言 虽然Java的泛型在语法上和C++相比是类似的,但在实现上两者是全然不同的. 语法 Java只需要一个<>就可定义泛型.在<> ...
- Java学习点滴——Class和反射
基于<Java编程思想>第四版 前言 我们要操作一个类实例对象时,一般都要先知道这个类有哪些方法或者成员变量.反射就是在我们不知道这个类有哪些方法或成员变量时,使用特定方式得到类的这些信息 ...
- java学习-Comparable<Integer>接口方法的实现
基本数据类型的包装类Integer, Float, Double,Long,Byte等都实现的Comparable接口,用于列表List或数组arrays的排序 Comparable<Integ ...
- Java学习点滴——对象实例化
基于<Java编程思想>第四版 构造与析构 在C++中通过构造函数和析构函数来保证:对象在使用前被正确初始化,在使用后被正确回收.Java中同样存在构造函数,但是没有析构函数.之所以没有析 ...
- 从.Net到Java学习第七篇——SpringBoot Redis 缓存穿透
从.Net到Java学习系列目录 场景描述:我们在项目中使用缓存通常都是先检查缓存中是否存在,如果存在直接返回缓存内容,如果不存在就直接查询数据库然后再缓存查询结果返回.这个时候如果我们查询的某一个数 ...
- java中字面量,常量和变量之间的区别(附:Integer缓存机制)
一.引子 在各种教科书和博客中这三者经常被引用,今天复习到内存区域,想起常量池中就是存着字面量和符号引用,其实这三者并不是只在java中才有,各个语言中都有类似的定义,所以做一下总结,以示区分. 二. ...
- Java常量池详解之Integer缓存
一个Java question,求输出结果 public class IntegerTest { public static void main(String[] args) { objPoolT ...
随机推荐
- kubernetes 微服务西游记(持续更新中...)
随着微服务架构的流行,迈向云原生的趋势,容器化微服务就成为了持续集成最好的手段,镜像成为了持续交付最好的产物,容器成为了镜像运行最好的环境,kubernetes成了部署容器最好的生态系统和规范.实践出 ...
- Airtest 快速上手教程
一.Airtest 简介: AirtestIDE 是一个跨平台的UI自动化测试编辑器,适用于游戏和App. 自动化脚本录制.一键回放.报告查看,轻而易举实现自动化测试流程 支持基于图像识别的 Airt ...
- Java语言编程 - Java第一个程序HelloWorld
3.1 新建Java文件 首先新建一个文件夹,用于存放写的Java程序,例如我存放Java程序的位置为” D:\Files\code\java”. 在该文件夹中,右键新建一个文本文档 将文件名重命名为 ...
- docker常规操作——启动、停止、重启容器实例
一.启动一个已经停止的容器实例 docker start 容器ID或容器名,建议使用容器ID,容器ID支持模糊查询而容器名称不支持1. 先查看已经暂停的容器实例信息 2. 通过docker start ...
- cshtml中正则表达式使用后台代码
//定义变量 bool a = false; //正则表达式 string b = @" ^ (13[0 - 9] | 14[5 | 7] | 15[0 | 1 | 2 | 3 | 5 | ...
- HTML5和CSS3的新特性
html5的新特性 添加了用于媒介回放的 <video>,<audio> 元素 添加了语义标签譬如 header.footer.nav 等等元素 添加了用于绘画的 canvas ...
- Android studio无法创建类和接口问题解决办法。提示 Unable to parse template "Class"
重新配置了studio 的工作环境, 没问题,后来加需求要新增java类和接口,这就出现问题了,新建的时候,就会报错: Unable to parse template "Interface ...
- Vagrant 构建 Linux 开发环境
Vagrant 是一个简单易用的部署工具,用英文说应该是 Orchestration Tool .它能帮助开发人员迅速的构建一个开发环境,帮助测试人员构建测试环境, Vagrant 基于 Ruby 开 ...
- 接触新的项目,构建时候报错:Failure to find io.netty:netty-tcnative:jar:${os.detected.classifier}:2.0.7.Final in
详细信息如下: Failure to find io.netty:netty-tcnative:jar:${os.detected.classifier}:2.0.7.Final in http:// ...
- javascript中apply、call和bind的区别及方法详解
文章目录 apply.call apply.call 区别 apply.call实例 数组之间追加 获取数组中的最大值和最小值 验证是否是数组(前提是toString()方法没有被重写过) 类(伪 ...