55 | 享元模式(下):剖析享元模式在Java Integer、String中的应用
王争
该思维导图由 AI 生成,仅供参考
上一节课,我们通过棋牌游戏和文本编辑器这样两个实际的例子,学习了享元模式的原理、实现以及应用场景。用一句话总结一下,享元模式中的“享元”指被共享的单元。享元模式通过复用对象,以达到节省内存的目的。
今天,我再用一节课的时间带你剖析一下,享元模式在 Java Integer、String 中的应用。如果你不熟悉 Java 编程语言,那也不用担心看不懂,因为今天的内容主要还是介绍设计思路,跟语言本身关系不大。
话不多说,让我们正式开始今天的学习吧!
享元模式在 Java Integer 中的应用
我们先来看下面这样一段代码。你可以先思考下,这段代码会输出什么样的结果。
如果不熟悉 Java 语言,你可能会觉得,i1 和 i2 值都是 56,i3 和 i4 值都是 129,i1 跟 i2 值相等,i3 跟 i4 值相等,所以输出结果应该是两个 true。这样的分析是不对的,主要还是因为你对 Java 语法不熟悉。要正确地分析上面的代码,我们需要弄清楚下面两个问题:
如何判定两个 Java 对象是否相等(也就代码中的“==”操作符的含义)?
什么是自动装箱(Autoboxing)和自动拆箱(Unboxing)?
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
Java中的享元模式在Integer和String类中的应用是非常重要的。通过对Java中的自动装箱和自动拆箱的理解,我们可以看到Integer类利用享元模式来缓存-128到127之间的整型值,以节省内存空间。这种机制使得在创建整型对象时,可以复用已存在的对象,而不是每次都创建新的对象,从而提高了内存利用率。String类也利用享元模式来复用相同的字符串常量,通过JVM开辟的字符串常量池来存储字符串常量,从而节省内存空间。然而,享元模式对JVM的垃圾回收并不友好,因为享元工厂类一直保存了对享元对象的引用,导致对象即使在没有任何代码使用的情况下也不会被JVM垃圾回收机制自动回收掉。因此,在某些情况下,利用享元模式可能会浪费更多的内存。除非经过线上验证,利用享元模式真的可以大大节省内存,否则,就不要过度使用这个模式。文章还提出了一个思路,即在程序的运行过程中,当用到某个整型对象的时候,创建好放置到IntegerCache,下次再被用到的时候,直接从IntegerCache中返回,并且能够做到在某个对象没有任何代码使用的时候,能被JVM垃圾回收机制回收掉。这篇文章通过具体的代码示例和内存存储结构图的解释,帮助读者理解了Java中享元模式的应用,适合Java开发者快速了解享元模式在Integer和String中的应用,以及如何在实际开发中充分利用这一特性来提升性能。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《设计模式之美》,新⼈⾸单¥98
《设计模式之美》,新⼈⾸单¥98
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(48)
- 最新
- 精选
- 一丨丿丶乙享元--->复用,线程池等。通过复用对象,以达到节省内存的目的 1.懒加载,dubble check 2.weak reference持有享元对象
作者回复: 嗯嗯 ������
2020-11-181 - 张三丰为什么说垃圾回收的时候如果保存了对象的"引用"就不友好,垃圾回收的依据不是只看这个对象还有没有被"使用"吗?
作者回复: 有引用,就是在被使用啊
2020-07-31 - Liam享元池用weak reference持有享元对象2020-03-09775
- 小晏子如果IntegerCache不事先指定缓存哪些整形对象,那么每次用到的时候去new一个,这样会稍微影响一些效率,尤其在某些情况下如果常用到-128~127之间的数,可能会不停的new/delete, 不过这个性能问题在大部分时候影响不是很大,所以按照string的设计思路也是可行的, 按照这个思路设计IntegerCache类的话,如下 private static class IntegerCache { public static final WeakHashMap<Integer, WeakReference<Integer>> cache = new WeakHashMap<Integer, WeakReference<Integer>>(); //也可以提前分配容量 private IntegerCache(){} } public static Integer valueOf(int i) { final WeakReference<Integer> cached = IntegerCache.cache.get(i); if (cached != null) { final Integer value = cached.get(i); if (value != null) { return value; } } WeakReference<Integer> val = new WeakReference<Integer>(i); IntegerCache.cache.put(i, val); return val.get(); }2020-03-09751
- 辣么大谢谢各位的讨论,今天学到了软引用,弱引用,和WeakHashMap。内存吃紧的时候可以考虑使用WeakHashMap。 https://www.baeldung.com/java-weakhashmap https://www.baeldung.com/java-soft-references https://www.baeldung.com/java-weak-reference2020-03-11747
- 李小四设计模式_55: # 作业 原来还有个WeakHashMap,学习了。 # 感想 自己尝试了写了一个,然后分别测试了10,000次、100,000次,1,000,000次创建,value从1-100,100-200,10000-10100,发现不管哪个场景,总是JVM的Integer时间更短,我写的要3倍左右的时间,不禁感叹,Java二十几年了,大部分的优化应该都做了,不要期望自己花20分钟能改出超过JVM的性能。2020-03-1730
- 3Spiders课后题。因为整型对象长度固定,且内容固定,可以直接申请一块连续的内存地址,可以加快访问,节省内存?而String类不行。2020-03-09125
- Geek_41d472我勒个擦 ,这好像是我碰到的两道面试题,包装和拆箱这道题简直就是个坑,有踩坑的举个手2020-03-1013
- webmin抛砖引玉实现了一个有限范围的缓存(-128~2048383(127 * 127 * 127)) public class IntegerCache { private static final int bucketSize = 127; private static final int level1Max = bucketSize * bucketSize; private static final int max = bucketSize * bucketSize * bucketSize; private static final WeakHashMap<Integer, WeakHashMap<Integer, WeakHashMap<Integer,WeakReference<Integer>>>> CACHE = new WeakHashMap<>(); public static Integer intern(int integer) { if (integer <= 127) { return integer; } if (integer > max) { return integer; } synchronized (CACHE) { Integer l1 = 0; int tmp = integer; if(integer >= level1Max){ l1 = integer / level1Max; integer -= level1Max; } Integer l2 = integer / bucketSize; Integer mod = integer % bucketSize; WeakHashMap<Integer, WeakHashMap<Integer,WeakReference<Integer>>> level1 = CACHE.computeIfAbsent(l1, val -> new WeakHashMap<>()); WeakHashMap<Integer,WeakReference<Integer>> level2 = level1.computeIfAbsent(l2, val -> new WeakHashMap<>()); WeakReference<Integer> cache = level2.computeIfAbsent(mod, val -> new WeakReference<>(tmp)); Integer val = cache.get(); if (val == null) { val = integer; level2.put(mod, new WeakReference<>(val)); } return val; } } public static int integersInCache() { synchronized (CACHE) { int sum = CACHE.size(); for (Integer key : CACHE.keySet()) { WeakHashMap<Integer, WeakHashMap<Integer,WeakReference<Integer>>> tmp = CACHE.get(key); sum += tmp.size(); for(Integer l2Key : tmp.keySet()) { sum += tmp.get(l2Key).size(); } } return sum; } } }2020-03-09110
- Eden Ma突然理解OC中NSString等也用到了享元设计模式.2020-03-0929
收起评论