首页 > 其他分享 >浅谈包装类缓存池技术

浅谈包装类缓存池技术

时间:2022-11-15 13:00:39浏览次数:72  
标签:拆箱 缓存 浅谈 包装 System 对象 println Integer out

  • 回顾包装类的装箱和拆箱
  public class IntegerTest{
	  public static void main(String[]args){
		 Integer i=new Integer(4);//手动装箱 调用构造方法
		 Integer a=5;//自动装箱  自动调用valueOf方法
		 int b=i.intValue();//手动拆箱 调用intValue方法
		 int e=a;//自动拆箱 自动调用intValue方法
		 
	  }
  }

我们可以发现两种方法的拆箱调用的函数相同,但在装箱时调用的函数不同,下面我们将重点分析拆箱两种方法的优劣

Integer i = new Integer(xxx)和Integer i =xxx的区别

  • Integer i =xxx
    在实际进行时将自动调用valueOf()方法,该方法函数头为public static Integer valueOf(int i)返回一个对象,所有的基本类型都有这个方法,根据类不同返回不同类的对象
  • 包装类常量池(缓冲池技术)(以Integer类举例)
    在java中所有的包装类都有一个常量池,会将各种类数值在一定范围的对象被创建,在常量池(对象池)中Integer已经默认创建了数值【-128-127】的Integer缓存数据。所以使用Integer a=1时,JVM会直接在该在对象池找,找到该对象则直接指向值为1的对象。也就是说这种方式声明一个Integer对象时,JVM首先会在Integer对象的缓存池中查找有木有值为1的对象,如果有直接返回该对象的引用; 但是如果数值超出了这个范围,就将不会以这种方法创建对象,此时将会调用 new Integer()创建一个对象

这种方法可以推断出其创建对象的效率或者说速度会有很大的提升,但同时也可以发现他将极大的消耗内存,这是一个以以空间换时间的策略

  • Integer i = new Integer(xxx)
    用该类的构造方法创建对象,这是一个普遍的创建对象的方式,每次创建将会在堆中开辟一块内存用于存放对象

两种方式的区别
1)第一种方式不会触发自动装箱的过程;而第二种方式会触发;

    2)在执行效率和资源占用上的区别。第二种方式的执行效率和资源占用在一般性情况下要优于第一种情况,当值不在(-128-127)之间时(注意这并不是绝对的)。

  • 缓冲池作用理解举例
Integer x = new Integer(123);
Integer y = new Integer(123);
System.out.println(x == y);    // false
Integer z = Integer.valueOf(123);
Integer k = Integer.valueOf(123);
System.out.println(z == k);   // true
------

原文链接:https://pdai.tech/md/java/basic/java-basic-lan-basic.html

new Integer(123) 与 Integer.valueOf(123) 的区别在于:
new Integer(123) 每次都会新建一个对象Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用

此时valueOf方法的实现源码

public static Integer valueOf(int i) {
    final int offset = 128;
    if (i >= -128 && i <= 127) { // must cache
        return IntegerCache.cache[i + offset];
    }
        return new Integer(i);
}

先判断其是否在常量池中,如果在的话则直接返回缓冲池里面的内容

  //验证缓存池技术
  public class IntegerTest{
	  public static void main(String[]args){
		 Integer i=456;
		 Integer a=456;
		 System.out.println(i==a);//false
		 
	  }
  }

当超出其常量池的范围将会以构造函数的方式创建对象

看下面一个例子


  //验证缓存池技术
  public class IntegerTest{
	  public static void main(String[]args){
		 Double i=34.3;
		 Double j=34.3;
		 Double a=2.1;
		 Double b=2.1;
		 System.out.println(i==j);//false
		 System.out.println(a==b);//false
		 
		 
	  }
  }

可能会以为会输出true,但实际为false,在这里只解释一下为什么Double类的valueOf方法会采用与Integer类的valueOf方法不同的实现。很简单:在某个范围内的整型数值的个数是有限的,而浮点数却不是。

对包装类的valueOf进行总结
Integer派系: Integer Short Character Boolean Long的valueOf的实现是类似的
Double派系: Double Float的实现是类型的,每次返回不同的对象

一个例子说明一些情况

public class Main {
    public static void main(String[] args) {
         
        Integer a = 1;
        Integer b = 2;
        Integer c = 3;
        Integer d = 3;
        Integer e = 321;
        Integer f = 321;
        Long g = 3L;
        Long h = 2L;
         
        System.out.println(c==d);
        System.out.println(e==f);
        System.out.println(c==(a+b));
        System.out.println(c.equals(a+b));
        System.out.println(g==(a+b));
        System.out.println(g.equals(a+b));
        System.out.println(g.equals(a+h));
    }
}

以上代码原文

false
true
true
true
false
true

一些必知知识点

  • ==比较的是对象的地址
  • Object类的equals函数也是实现的地址的比较,如果其子类没有将equals函数覆写,调用equals函数将会调用Object类的equals
  • 当包装类的对象进行运算时会自动发生发生装箱和拆箱操作
    举例:
  public class IntegerTest{
	  public static void main(String[]args){
		int e=2;  
		Integer a=4;
		Integer b=5;
		Integer f=a+e;//a先拆箱成基本类型完成计算然后装箱成对象
		Integer c=a+b;//a 和b先自动拆箱进行计算然后又装箱成对象
		Integer d=a*b;//a和b先 拆箱进行计算然后装箱成对象
		System.out.println(f);//自动拆箱成基本类型
		System.out.println(c);//该过程会自动拆箱为基本类型输出
		System.out.println(d);//该过程会自动拆箱为基本类型输出
	  }
  }
  output:
6
9
20

当对象和对象或者对象和基本类型进行一些运算时,可以用自动拆箱和装箱,使其运算变得合理

  • 对于包装器类型,equals方法并不会进行类型转换

输出解释
第二个因为超出了常量池的范围,调用了构造方法创建了对象,地址值不同。第三个先会进行括号里的运算,先自动拆箱进行运算然后装箱成对象。第四个和第三个相同。第五个对象的类型不同将会进行对象的类型转换,所有为true。第六个对象类型不同但equals方法不能进行对象类型的转换所有为false。第七个括号里面先会自动拆箱,然后基本类型会都转换成long进行运算,然后自动装箱为Long类,所有最后为true

参考:
https://pdai.tech/
https://www.cnblogs.com/Pjson/p/8777940.html

标签:拆箱,缓存,浅谈,包装,System,对象,println,Integer,out
From: https://www.cnblogs.com/swtaa/p/16891175.html

相关文章

  • config.cache 配置缓存fixture
    目录介绍函数缓存相关命令介绍config.cache是一个实例pytest.Cache:该config.cache对象允许其他插件和装置在测试运行中存储和检索值。要从fixtures请求访问它pytestco......
  • 聊聊FASTER和进程内混合缓存
    最近有一个朋友问我这样一个问题:我的业务依赖一些数据,因为数据库访问慢,我把它放在Redis里面,不过还是太慢了,有什么其它的方案吗?其实这个问题比较简单的是吧?Redis其实属......
  • Memcached内存缓存服务
       内存缓存(Memcached)是一个开源的、高性能的分布式内存对象缓存系统。通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高网站访问速度,加速动态WEB应用、......
  • 【Azure Redis 缓存】Linux VM使用6380端口(SSL方式)连接Azure Redis (redis-cli & st
    本文介绍使用LinuxVM如何连接到AzureRedis,通过SSL方式(6380)或非SSL方式(6379)问题描述在AzureRedis的官方文档中,介绍了在Windows下,如何通过redis-cli.exe连接Redi......
  • 如何在调试页面的时候清除页面的缓存?
    1.按F12,弹出下图2.点击右上角的三个点:3.点击settings  4.找到Network,下面的Disablecache(whileDevToolsisopen) ......
  • Thread - 01 -浅谈synchronized的作用
    浅谈synchronized的作用售票demopublicclassdemo{publicstaticvoidmain(String[]args){Threadt1=newThread(newSaleThread(),"售票人员1")......
  • 【Azure Redis 缓存】Redis 连接失败
    问题描述AzureRedis出现连接失败,过一会儿后,又能自动恢复。 问题解答其实,因为AzureRedis服务一直都有升级维护的操作(平均每月一次),Redis服务更新是平台自动进行的......
  • redis缓存雪崩
              代码实现:互斥锁packagecom.hmdp.utils;importcn.hutool.core.util.BooleanUtil;importcn.hutool.core.util.StrUtil;importcn.hutool.......
  • redis中缓存穿透
         代码实现 //Stringkey=CACHE_SHOP_KEY+id;////1从缓存中查询上铺缓存//StringshopJson=stringRedisTemplate.opsForVa......
  • 小白教程 懒人听书音频文件乱码,缓存音频文件名解码mp3教程
    通过懒人听书app下载下来的音频文件是乱码,直接通过播放器打开文件是播放不了的,那么想将音频文件分享给朋友随时随地听,怎么办? 如果能够直接下载MP3格式的音频文件,那......