结合JDK源码看设计模式——享元模式
前言
在说享元模式之前,你一定见到过这样的面试题
public class Test {
public static void main(String[] args) {
Integer a=Integer.valueOf(127);
Integer b=new Integer(127);
System.out.println(a==b);
int c=127;
System.out.println(a==c);
System.out.println(b==c);
}
}
问你输出结果是什么?有些人可能一下就看出了答案是什么,有些人可能不是特别清楚。那么一起看下面的文章。我想你很快就能知晓。
一、享元模式定义
提供了减少对象数量从而改善应用所需的对象结构方式,使用共享技术有效地支持大量细粒度的对象。
二、适用场景
常用于系统底层开发,以便解决系统的性能问题。像数据库连接池,里面都是创建好的连接对象,在这些连接对象中有我们需要的则直接拿来用,避免重新创建。如果没有我们需要的,则创建一个。
在一个系统中有大量相似对象,需要缓冲池的场景。不需要一直创建一个新的对象,可以直接从缓冲池里拿。这样可以降低系统内存,同时提高效率。
三、内部状态与外部状态
内部状态:
在享元模式内部,不随外界的改变而改变。比如说Integer类中的MIN_VALUE和MAX_VALUE两个值,无论外部传什么值。都不会改变这两个值。
外部状态:
这就很好理解了,就是随外部的改变而改变的状态。比如说Integer类中的value值。
四、Integer中的享元模式
经过上面的介绍,你肯定大概了解了享元模式的概念。那么我们来看看Integer中的享元模式具体是怎么样的吧。
public final class Integer extends Number implements Comparable<Integer> {
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
private final int value;
public Integer(int value) {
this.value = value;
}
}
上面是我简化了的Integer类。平常在使用Integer类的时候。你是否思考过用valueOf还是用new创建Integer对象。看完源码就会发现在valueOf这个方法中它会先判断传进去的值是否在IntegerCache中,如果不在就创建新的对象,在就直接返回缓存池里的对象。这个valueOf方法就用到享元模式。它将-128到127的Integer对象先在缓存池里创建好,等我们需要的时候直接返回即可。所以在-128到127中的数值我们用valueOf创建会比new更快。如果你还想继续往里钻研,可以去看看IntegerCache如何实现。在这里我们主要说设计模式。看接下来的一个测试代码及内存分析。

这里就可以很清晰的看出来a和b的内存不相等。结果当然是false。回到我们的设计模式上来,在实际的场景中我们更多的是完成缓冲池的创建,来达到缓冲池对象里面复用的功能。就像下面这种情况,尽管我定义了两个不同的对象,但实际上我指向的是同一块内存地址,这样就减少了系统内存,并且使系统的响应速度更快。

五、总结
在享元模式里我们要理解享元,“享”就表示共享,“元”表示对象。当我们频繁需要这个对象的时候,我们考虑new,考虑clone等等这些方法。当然这些方法实际上用的场景和这个不一样。看上面的内存分析就能知道,我们频繁需要相同的一个范围内的对象去做某件事情,我们还需要重新创建对象就会有两个缺点:第一就是内存浪费,第二就是性能稍慢,特别是我这个对象new起来需要响应的时间很长的时候。这时候考虑用享元模式来先创建一个缓冲池会更好。这个缓冲池可以放在容器中进行存储,当我们需要的时候直接拿出来用即可。一次创建,多次使用。
在这里多说一点就是当int类型和Integer比较的时候会自动的拆箱也就是只比较里面的值大小是否相等,所以上面的答案就是false,true,true。
结合JDK源码看设计模式——享元模式的更多相关文章
- 结合JDK源码看设计模式——装饰者模式
定义 在不改变原有对象的基础之上,将功能附加到对象上 适用场景 扩展一个类的功能 动态的给对象增加功能,当功能不需要的时候能够动态删除 详解 在看到定义的时候,可能很多人会想,这不就是继承吗?的确很像 ...
- 结合JDK源码看设计模式——桥接模式
前言: 在我们还没学习框架之前,肯定都学过JDBC.百度百科对JDBC是这样介绍的[JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Jav ...
- 结合JDK源码看设计模式——单例模式
定义: 保证一个类仅有一个实例,并提供一个全局访问点 适用场景: 确保任何情况下这个对象只有一个实例 详解: 私有构造器 单利模式中的线程安全+延时加载 序列化和反序列化安全, 防止反射攻击 结合JD ...
- 结合JDK源码看设计模式——原型模式
定义: 指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.不需要知道任何创建的细节,不调用构造函数适用场景: 类初始化的时候消耗较多资源 new产生的对象需要非常繁琐的过程 构造函数比较 ...
- 结合JDK源码看设计模式——简单工厂、工厂方法、抽象工厂
三种工厂模式的详解: 简单工厂模式: 适用场景:工厂类负责创建的对象较少,客户端只关心传入工厂类的参数,对于如何创建对象的逻辑不关心 缺点:如果要新加产品,就需要修改工厂类的判断逻辑,违背软件设计中的 ...
- 结合JDK源码看设计模式——模板方法模式
前言: 相信很多人都听过一个问题:把大象关进冰箱门,需要几步? 第一,把冰箱门打开:第二,把大象放进去:第三,把冰箱门关上.我们可以看见,这个问题的答案回答的很有步骤.接下来我们介绍一种设计模式--模 ...
- 结合JDK源码看设计模式——适配器模式
定义: 将一个类的接口转换成客户期望的另外一个接口(重点理解适配的这两个字),使得接口不兼容的类可以一起工作适用场景: 已经存在的类,它的方法和需求不匹配的时候 在软件维护阶段考虑的设计模式 详解 首 ...
- 结合JDK源码看设计模式——迭代器模式
前言: Iterator翻译过来就是迭代器的意思.在前面的工厂模式中就介绍过了iterator,不过当时介绍的是方法,现在从Iterator接口的设计来看,似乎又是一种设计模式,下面我们就来讲讲迭代器 ...
- 结合JDK源码看设计模式——建造者模式
概念: 将一个复杂对象的构建与它的表示分离.使得同样构建过程可以创建不同表示适用场景: 一个对象有很多属性的情况下 想把复杂的对象创建和使用分离 优点: 封装性好,扩展性好 详解: 工厂模式注重把这个 ...
随机推荐
- mysql根据查询结果批量更新多条数据(插入或更新)
mysql根据查询结果批量更新多条数据(插入或更新) 1.1 前言 mysql根据查询结果执行批量更新或插入时经常会遇到1093的错误问题.基本上批量插入或新增都会涉及到子查询,mysql是建议不要对 ...
- vscode设置
通过ctrl+滚轮实现字体大小改变:在文件-->首选项-->设置-->用户设置中添加如下代码:"editor.mouseWheelZoom": true,
- Devexpress Ribbon 动态生成菜单
/// <summary> /// 动态加载菜单 /// </summary> private void GetMenuBind() { //根据登录用户角色菜单动态创建 // ...
- sha256 js 前端加密
<html> <head></head> <body> <script type="text/javascript" src= ...
- #Java学习之路——基础阶段(第九篇)
我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...
- [Swift]LeetCode391. 完美矩形 | Perfect Rectangle
Given N axis-aligned rectangles where N > 0, determine if they all together form an exact cover o ...
- [Swift]LeetCode515. 在每个树行中找最大值 | Find Largest Value in Each Tree Row
You need to find the largest value in each row of a binary tree. Example: Input: 1 / \ 3 2 / \ \ 5 3 ...
- [Swift]LeetCode650. 只有两个键的键盘 | 2 Keys Keyboard
Initially on a notepad only one character 'A' is present. You can perform two operations on this not ...
- 页面的div中有滚动条,js实现刷新页面后回到记录时滚动条的位置
当div中绑定数据,给它一个属性overflow-y: scroll,添加长度大小,使其能够出现滚动条:每次刷新的时候滚动条总是会出现在最上方,这使我很头疼,经过查阅网上资料,返现两种方法可行.如下: ...
- Jquery 对DOM 的操作
.focus 获取焦点 .blus离开焦点----------------------------------------------------------------------------- ...