享元模式
享元模式
享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象。
具体来讲,当一个系统中存在**大量重复对象的时候,如果这些重复的对象是不可变对象,我们就可以利用享元模式将对象设计成享元,**在内存中只保留一份实例,供多处代码引用。这样可以减少内存中对象的数量,起到节省内存的目的。实际上,不仅仅相同对象可以设计成享元,对于相似对象,我们也可以将这些对象中相同的部分(字段)提取出来,设计成享元,让这些大量相似对象引用这些享元。
Integer是一个经典的享元模式应用
1 | Integer i1 = 56; |
我们来看看这段代码,首先我们可以很明确的知道i1和i2都是56,i3和i4都是129,所以从数值上看他们都是相等的,但是他们的结果都是true吗?
其实不然,这里 ’==‘运算符比较的是两个对象之间的地址是否相等,这里四个对象的创建都是使用了自动装箱,Integer会根据数值自动的为他们创建一个数值相等的Integer对象,那么这四个对象都是不一样的,所以两个结果都是falsse吗?
实际上这段代码运行的结果是true和false,那么为什么只在数值上不同的二者运行的结果会不相同呢,这就是Java底层使用的享元模式
实际上在自动装箱的过程Integer会隐式调用valueOf方法,我们观察源码
1 | public static Integer valueOf(int i) { |
可以看到在valueOf方法中,如果对象在high和low之间,那么则会从IntegerCache中返回一个对象,low和high默认是-128和127,所以上面i1和i2自动装箱得到的对象是相同的
String类中也有用到享元模式,我们都直到,Java中的字符串是不可变的,他们都存储在常量池中,当我们在使用自动装箱方法创建String对象时,会先从常量池中寻找是否已经存在该字符串,如果存在则直接引用,不存在才会创建String
享元模式应用在程序中可以大量的减少内存的消耗
比如我们要设计一个下棋游戏,每一个棋盘中的棋子都是固定的,在不同棋盘中的棋子只是位置不同,这个时候我们就可以使用享元模式,让所有棋盘共享同一批棋子减少内存的消耗