在进行java开发的你是否有遇到过这样的情况?
有两个字面量一样Integer,当用==进行比较的时候,有的时候是true,有的时候是false。老鸟们会告诫说包装类不能用==进行比较,得用equals。这是为什么?
其实当字面量赋值给包装类时,字面量在-128到127之间,用==进行比较是相同的。但是超过这个范围的Integer们比较起来就是false了。其实Integer使用到了享元模式,在-128到127的范围内的所有Integer都是同一个对象,超过这个范围的都是新创建的对象。
那什么是享元模式?
享元(FlayWeight)模式,通过共享一系列相同或者相似的对象实例,用来减少系统中的内存占用。
在JVM启动的伊始,Integer们就会创建出-128到127的一系列实例出来缓存起来(因为大家发现这个范围内的int们使用率特别地高),当在程序中使用Integer a = 1; 的时候,会直接返回缓存的对象,所以当Integer b = 1;的时候,返回的也是给a的对象实例。因为Integer(1)这个对象实例是被缓存起来的。
以上的描述,会不会让你想起另外一个设计模式?
对,一个叫单例模式的思想也是通过共用一个对象来减少系统中的内存占用。但他们的区别有如下几点:
1、单例是类级别的,关注的是一个类只有一个实例。而享元是对象级别的,一个类可以有多个对象,大家可以共享这些对象。
2、单例主要解决的痛点是这个类的实例不会有很大的变动,但是创建起来较为复杂,所以只创建一个,大家都可以用这一个。享元关注的是一些小的,细粒度的对象,可能会在系统中被创建很多很多个,但是内容都大同小异,所以缓存起一些常用的,避免重复创建。
3、单例会严格控制实例的创建(只能是它自己创建,其他客户端只有通过它的getInstance方法获取实例)。而享元模式可以直接获取它缓存的实例,也可以创建新的实例,例如Integer c = 128; 和 Integer d = new Integer(1); 都是创建了新的实例。
还有哪些常用的场景到了享元?
1、部分包装类型:Boolean [true,false],Byte [-128,127],Short [-128,127],Long [-128,127],Charactor [-128,127], Integer [-128,127]。而Float和Double是没有缓存任何字面量的。
2、所有池化思想的地方,例如线程池,数据库连接池
3、游戏中:象棋,围棋,纸牌,怪物。他们都是有大量相同的属性,也会产生大数量的实例。
网友评论