前言

一切从下面这段代码开始

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();
    }
}

执行后发现ab引用对象的值确实交换了。

但是在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。

由此就可以知道,因为ab引用的是cache中的对象,swap()后,cache中对象的值和其在数组中的下标已经不对应了,所以c引用的对象的实际值是2。

为了避免交换影响到Integer的缓存,我们必须使用new来实例化ab引用的对象。

结语

Java似乎就是有意不让程序员去修改对象内存的,只能改改引用的对象,像String的替换、追加等操作,都是返回一个新实例化的对象,而不是在原对象的内存中修改。

Java学习点滴——Integer缓存的更多相关文章

  1. Java学习点滴——初识Java

    基于<Java编程思想>第四版 前言 "程序就是算法加数据结构",而算法就是控制语句加操作符,编写一个程序就是使用控制语句加操作符去操作数据结构,因此我从Java的控制 ...

  2. java封装数据类型——Integer 缓存策略验证

    上一篇学习 Integer 类型源码,知道了它使用缓存策略,默认对 [-128, 127] 范围的对象进行类加载时自动创建缓存. Integer 源码学习:https://www.cnblogs.co ...

  3. Java学习点滴——泛型

    基于<Java编程思想>第四版 前言 虽然Java的泛型在语法上和C++相比是类似的,但在实现上两者是全然不同的. 语法 Java只需要一个<>就可定义泛型.在<> ...

  4. Java学习点滴——Class和反射

    基于<Java编程思想>第四版 前言 我们要操作一个类实例对象时,一般都要先知道这个类有哪些方法或者成员变量.反射就是在我们不知道这个类有哪些方法或成员变量时,使用特定方式得到类的这些信息 ...

  5. java学习-Comparable<Integer>接口方法的实现

    基本数据类型的包装类Integer, Float, Double,Long,Byte等都实现的Comparable接口,用于列表List或数组arrays的排序 Comparable<Integ ...

  6. Java学习点滴——对象实例化

    基于<Java编程思想>第四版 构造与析构 在C++中通过构造函数和析构函数来保证:对象在使用前被正确初始化,在使用后被正确回收.Java中同样存在构造函数,但是没有析构函数.之所以没有析 ...

  7. 从.Net到Java学习第七篇——SpringBoot Redis 缓存穿透

    从.Net到Java学习系列目录 场景描述:我们在项目中使用缓存通常都是先检查缓存中是否存在,如果存在直接返回缓存内容,如果不存在就直接查询数据库然后再缓存查询结果返回.这个时候如果我们查询的某一个数 ...

  8. java中字面量,常量和变量之间的区别(附:Integer缓存机制)

    一.引子 在各种教科书和博客中这三者经常被引用,今天复习到内存区域,想起常量池中就是存着字面量和符号引用,其实这三者并不是只在java中才有,各个语言中都有类似的定义,所以做一下总结,以示区分. 二. ...

  9. Java常量池详解之Integer缓存

    一个Java question,求输出结果   public class IntegerTest { public static void main(String[] args) { objPoolT ...

随机推荐

  1. sau交流学习社区第三方登陆github--oauth来实现用户登录

    sau交流学习社区第三方登陆github--oauth来实现用户登录 最近在丰富nodejsBlog开发的“交流学习社区”(https://www.mwcxs.top)的其他功能以及修复一些bug. ...

  2. Servlet底层原理、Servlet实现方式、Servlet生命周期

    Servlet简介 Servlet定义 Servlet是一个Java应用程序,运行在服务器端,用来处理客户端请求并作出响应的程序. Servlet的特点 (1)Servlet对像,由Servlet容器 ...

  3. 马蜂窝搜索基于 Golang 并发代理的一次架构升级

    搜索业务是马蜂窝流量分发的重要入口.很多用户在使用马蜂窝时,都会有目的性地主动搜索与自己旅行需求相关的各种信息,衣食住行,事无巨细,从而做出最符合需求的旅行决策. 因此在马蜂窝,搜索业务交互的下游模块 ...

  4. NET微信公众号开发环境搭建(一)-了解微信由来

    公众号的应用,开发及调试环境搭建 花生壳要注册 需要二十多块钱 ,还要实名认证,估计要一两天才能审核通过  主要就是在 windows搭建测试环境   1.微信的应用场景   360百科微信简介 ht ...

  5. 基于百度AI开放平台的人脸识别及语音合成

    基于百度AI的人脸识别及语音合成课题 课题需求 (1)人脸识别 在Web界面上传人的照片,后台使用Java技术接收图片,然后对图片进行解码,调用云平台接口识别人脸特征,接收平台返回的人员年龄.性别.颜 ...

  6. css公共库——简介中超过长度显示省略号

    在简介.引言中常见:文字只有一排,超出宽度以省略号显示,像这样 实现方法:在公共库定义otw类 .otw{ overflow: hidden; text-overflow: ellipsis; whi ...

  7. Beanstalkd工作队列

    Beanstalkd工作队列Beanstalkd 是什么Beanstalkd是目前一个绝对可靠,易于安装的消息传递服务,主要用例是管理不同部分和工人之间的工作流应用程序的部署通过工作队列和消息堆栈,类 ...

  8. SQL2005打SP4补丁报错:无法安装Windows Installer MSP文件解决方案

    错误如图: 解决方案分享如下: 第一步:卸载下图红框圈住的玩艺. 第二步:把SP4补丁文件解压,找到下图红框圈住的玩艺: 第三步:重新运行SP4补丁安装文件,安装正常.

  9. ioremap_nocache() 函数的使用【转】

    本篇文章主要是在ioremap_nocache函数说明的基础上进行整理,加入该函数的用法简介. 函数原型 void __iomem * ioremap_nocache (unsigned long o ...

  10. JVM内存结构/JVM运行时数据区,以及堆内存的划分

    1.程序计数器: 程序计数器是线程私有的内存,JVM多线程是通过线程轮流切换并分配处理器执行时间的方式实现的,当线程切换后需要恢复到正确的执 行位置(处理器)时,就是通过程序计数器来实现的.此内存区域 ...