为什么java.lang.Integer.valueOf是一个享元模式?

10

为什么java.lang.Integer.valueOf是一个享元模式? 我尝试找到原因,但没有成功。


2
Flyweight pattern(享元模式)是一种软件设计模式,主要用于减少大量细粒度对象的内存消耗。它通过共享已创建的相似对象来减少对象的数量。在Java编程语言中,Integer类提供了一个名为valueOf(int)的方法,该方法返回表示指定int值的整数对象。这个方法通过缓存和重用经常使用的值来提高性能。 - axtavt
2个回答

17

如果我们查看valueOf的源代码,就可以得到一些提示:java.lang.Integer的源代码第638-643行:

public static Integer valueOf(int i) {
        assert IntegerCache.high >= 127;
        if (i >= IntegerCache.low && i <= IntegerCache.high)
             return IntegerCache.cache[i + (-IntegerCache.low)];
         return new Integer(i);
}

看起来Integer类维护了一个整数对象缓存,用于常见值。不是每次有人调用valueOf时都创建一个新的对象,而是返回一个已经存在的对象的引用。因此,如果多次调用Integer.valueOf(1),每次都会得到相同的对象(而不仅仅是等价对象)。


如果这个 if (i >= IntegerCache.low && i <= IntegerCache.high) 条件不成立,那么就会创建一个新对象。 - BOSS
1
这个答案适用于Sun VM中的具体实现。从技术上讲,JavaDoc与此问题相关。 - Mathias Schwarz
如果您不想使用缓存,是否可以使用 new Integer(1)? - Simon Kuang
从这里的代码来看,我认为您可以通过在JVM启动时给-XX:AutoBoxCacheMax=<size>赋值来更改正缓存的大小。但是,您无法更改负缓存的大小。 - Bill Naylor

6

听起来你被要求解决一道练习。

如果你用相同的参数两次调用该方法,它可能会返回相同的对象,从而限制内存使用。这符合享元模式的定义。


关键在于IntegerCache。就轻量级而言,它不会占用太多内存。如果使用相同的参数调用两次,将返回相同的对象,这种情况我很擅长处理。但是,如果我提供不同的参数并且每个新调用都缓存对象,该怎么办呢? - BOSS
如果给定两个不同的参数,结果应该是两个不同的对象。 - Mathias Schwarz
但是我的问题是,缓存对象可能会导致内存消耗。 - BOSS
没错,但是有解决方案。具体来说,可以使用WeakReference(http://download.oracle.com/javase/6/docs/api/java/lang/ref/WeakReference.html)来避免在进行缓存时浪费内存。 - Mathias Schwarz
进一步探究这个主题,我在以下网址找到了一篇文章: https://javax0.wordpress.com/2017/05/03/hacking-the-integercache-in-java-9/ 该文章建议您可以使用反射来黑客攻击IntegerCache类,以填充缓存中的随机数字(甚至在Java 9+中通过利用sun.misc.unsafe模块)。我想理论上您可以使用相同的方法来更改IntegerCache.low字段。 - Bill Naylor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接