zoukankan      html  css  js  c++  java
  • 结合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。

  • 相关阅读:
    韩式英语
    Daily dictation 听课笔记
    words with same pronunciation
    you will need to restart eclipse for the changes to take effect. would you like to restart now?
    glottal stop(britain fountain mountain)
    education 的发音
    第一次用Matlab 的lamada语句
    SVN的switch命令
    String的split
    SVN模型仓库中的资源从一个地方移动到另一个地方的办法(很久才解决)
  • 原文地址:https://www.cnblogs.com/Cubemen/p/10666164.html
Copyright © 2011-2022 走看看