前言

  在说享元模式之前,你一定见到过这样的面试题

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源码看设计模式——享元模式的更多相关文章

  1. 结合JDK源码看设计模式——装饰者模式

    定义 在不改变原有对象的基础之上,将功能附加到对象上 适用场景 扩展一个类的功能 动态的给对象增加功能,当功能不需要的时候能够动态删除 详解 在看到定义的时候,可能很多人会想,这不就是继承吗?的确很像 ...

  2. 结合JDK源码看设计模式——桥接模式

    前言: 在我们还没学习框架之前,肯定都学过JDBC.百度百科对JDBC是这样介绍的[JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Jav ...

  3. 结合JDK源码看设计模式——单例模式

    定义: 保证一个类仅有一个实例,并提供一个全局访问点 适用场景: 确保任何情况下这个对象只有一个实例 详解: 私有构造器 单利模式中的线程安全+延时加载 序列化和反序列化安全, 防止反射攻击 结合JD ...

  4. 结合JDK源码看设计模式——原型模式

    定义: 指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.不需要知道任何创建的细节,不调用构造函数适用场景: 类初始化的时候消耗较多资源 new产生的对象需要非常繁琐的过程 构造函数比较 ...

  5. 结合JDK源码看设计模式——简单工厂、工厂方法、抽象工厂

    三种工厂模式的详解: 简单工厂模式: 适用场景:工厂类负责创建的对象较少,客户端只关心传入工厂类的参数,对于如何创建对象的逻辑不关心 缺点:如果要新加产品,就需要修改工厂类的判断逻辑,违背软件设计中的 ...

  6. 结合JDK源码看设计模式——模板方法模式

    前言: 相信很多人都听过一个问题:把大象关进冰箱门,需要几步? 第一,把冰箱门打开:第二,把大象放进去:第三,把冰箱门关上.我们可以看见,这个问题的答案回答的很有步骤.接下来我们介绍一种设计模式--模 ...

  7. 结合JDK源码看设计模式——适配器模式

    定义: 将一个类的接口转换成客户期望的另外一个接口(重点理解适配的这两个字),使得接口不兼容的类可以一起工作适用场景: 已经存在的类,它的方法和需求不匹配的时候 在软件维护阶段考虑的设计模式 详解 首 ...

  8. 结合JDK源码看设计模式——迭代器模式

    前言: Iterator翻译过来就是迭代器的意思.在前面的工厂模式中就介绍过了iterator,不过当时介绍的是方法,现在从Iterator接口的设计来看,似乎又是一种设计模式,下面我们就来讲讲迭代器 ...

  9. 结合JDK源码看设计模式——建造者模式

    概念: 将一个复杂对象的构建与它的表示分离.使得同样构建过程可以创建不同表示适用场景: 一个对象有很多属性的情况下 想把复杂的对象创建和使用分离 优点: 封装性好,扩展性好 详解: 工厂模式注重把这个 ...

随机推荐

  1. Tomcat简单优化

    解决 有两种解决办法: 1)在Tomcat环境中解决 可以通过配置JRE使用非阻塞的Entropy Source. 在catalina.sh中加入这么一行:-Djava.security.egd=fi ...

  2. BOM与DOM操作

    BOM: OM-JavaScript是运行在浏览器中的,所以提供了一系列对象用于和浏览器窗口进行交互,这些对象主要包括window.document.location.navigator和screen ...

  3. 东软实习<3>

    今天学习过程和小节 主要对多线程,单例模式以及jdbc进行了一些深入着重的学习, 还有就是学习了如何使用java操作HDFS 主要是对于一些继承调用的使用等 1.封装JDBC,自定义范型 2.反射,自 ...

  4. libguestfs手册(1): 架构

    要编辑一个image,则运行下面的命令 guestfish -a ubuntutest.img ><fs> 会弹出一个命令行工具 运行run ><fs> run 我 ...

  5. [转]Setting Keystone v3 domains

    http://www.florentflament.com/blog/setting-keystone-v3-domains.html The Openstack Identity v3 API, p ...

  6. JS关于Date函数的格式化输出

    // 对Date的扩展,将 Date 转化为指定格式的String // 月(M).日(d).小时(h).分(m).秒(s).季度(q) 可以用 1-2 个占位符, // 年(y)可以用 1-4 个占 ...

  7. [Swift]LeetCode419. 甲板上的战舰 | Battleships in a Board

    Given an 2D board, count how many battleships are in it. The battleships are represented with 'X's, ...

  8. [Swift]LeetCode522. 最长特殊序列 II | Longest Uncommon Subsequence II

    Given a list of strings, you need to find the longest uncommon subsequence among them. The longest u ...

  9. 通信统计接口字段填充内容shell脚本

    现在通信行业上班,最麻烦的就是计算各个协议接口字段填充的内容是否正确.经历了小白似的一个个字段统计在到单个接口所有字段统计,然后到现在的多个接口一次统计.在大大节省了时间的同时,让自己有更充足的时间来 ...

  10. PHP实现登录注册

    一.首先实现一个PHP的简单登录注册的话 我们要简单的与后端定义一下接口和传输数据的方式 并且我们要有一个phpStudy服务器. 第一步:当我们点击注册按钮的时候数据库要接收到客户端请求的数据  第 ...