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 ...
随机推荐
- WebApi管理和性能测试工具WebApiBenchmarks
说到WebApi管理和测试工具其实已经非常多的了,Postman.Swagger等在管理和维护上都非常出色:在性能测试方面也有不少的工具如:wrk,bombardier,http_load和ab等等. ...
- 使用docker-compose 一键部署你的分布式调用链跟踪框架skywalking
一旦你的程序docker化之后,你会遇到各种问题,比如原来采用的本地记日志的方式就不再方便了,虽然你可以挂载到宿主机,但你使用 --scale 的话,会导致 记录日志异常,所以最好的方式还是要做日志中 ...
- 关于Mybatis的一些随笔
Mapper.xml头文件 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http:/ ...
- 设计模式 | 建造者模式/生成器模式(builder)
定义: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 结构:(书中图,侵删) 一个产品类 一个指定产品各个部件的抽象创建接口 若干个实现了各个部件的具体实现的创建类 一个 ...
- 一、Java 23 种设计模式简介
一.23种设计模式分类: 二.设计模式的六大原则: 1.开闭原则(Open Close Principle):对扩展开放,对修改关闭.在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效 ...
- JAVA的特性
JAVA有三大特性:封装,继承和多态 一. 封装 封装就是将类的信息隐藏在类内部,不允许外部程序直接访问,而是通过该类的方法实现对隐藏信息的操作和访问. 封装的实现 a. 需要修改属性的访问控制符(修 ...
- Android studio无法创建类和接口问题解决办法。提示 Unable to parse template "Class"
重新配置了studio 的工作环境, 没问题,后来加需求要新增java类和接口,这就出现问题了,新建的时候,就会报错: Unable to parse template "Interface ...
- PHP全栈学习笔记3
trim()函数,用于去除字符串首尾空格和特殊字符 返回的是去掉的空格和特殊字符后的字符串 string trim(string str [,string charlist]); str 要操作的字符 ...
- python爬虫数据解析之xpath
xpath是一门在xml文档中查找信息的语言.xpath可以用来在xml文档中对元素和属性进行遍历. 在xpath中,有7中类型的节点,元素,属性,文本,命名空间,处理指令,注释及根节点. 节点 首先 ...
- 跟我一起学opencv 第五课之图像的混合
*理论-线性混合操作 g(x) = (1-α)f0(x)+αf1(x) α的取值范围位0-1之间 f0(x)为图像1,f1(x)表示第二张图像 α是混合系数 g(x)是生成的图像,对每一个像素 ...