结合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源码看设计模式——建造者模式
概念: 将一个复杂对象的构建与它的表示分离.使得同样构建过程可以创建不同表示适用场景: 一个对象有很多属性的情况下 想把复杂的对象创建和使用分离 优点: 封装性好,扩展性好 详解: 工厂模式注重把这个 ...
随机推荐
- 编写输出“Hello world”
1.打开Eclipse---->点击文件 如图所示: 2. 然后在新建--->点击Java项目会出现下图框------>在项目名输入框中输入项目名并选择JRE----->点 ...
- LeetCode编程训练 - 回溯(Backtracking)
回溯基础 先看一个使用回溯方法求集合子集的例子(78. Subsets),以下代码基本说明了回溯使用的基本框架: //78. Subsets class Solution { private: voi ...
- TCP协议学习总结(上)
在计算机领域,数据的本质无非0和1,创造0和1的固然伟大,但真正百花齐放的还是基于0和1之上的各种层次之间的组合(数据结构)所带给我们人类各种各样的可能性.例如TCP协议,我们的生活无不无时无刻的站在 ...
- mantisbt的配置与安装
下载并安装wampserver; 安装时,提示SMTP服务器时,应正确填写邮箱的SMTP的服务器地址: 安装完成后,登录phpMyAdmin; 给原有的root用户创建密码,所有root用户: 创建一 ...
- [Swift]LeetCode730. 统计不同回文子字符串 | Count Different Palindromic Subsequences
Given a string S, find the number of different non-empty palindromic subsequences in S, and return t ...
- [Swift]LeetCode837. 新21点 | New 21 Game
Alice plays the following game, loosely based on the card game "21". Alice starts with 0 p ...
- Redis 设计与实现 (八)--排序、慢查询日志、监视器
一.排序 SORT <key> 对一个数字值的key进行排序 1.alpha 对字符串类型的键进行排序 2.asc / desc redis 默认升序排序asc desc 与之相反 3. ...
- 正交矩阵、EVD、SVD
原文地址:https://www.jianshu.com/p/1004dd342fe2 一.正交矩阵 二.EVD 特征值分解(Eigen Value Decomposition, EVD). 对于对称 ...
- Python档案袋( Socket 与 ScoketServer 通信 )
Socket有一个缓冲区,缓冲区是一个流,先进先出,发送和取出的可自定义大小的,如果取出的数据未取完缓冲区,则可能存在数据怠慢.其中[recv(1024)]表示从缓冲区里取最大为1024个字节,但实际 ...
- 英语笔记3(git)
一: To create a new branch and switch to it at the same time, you can run the git checkout command wi ...