在解决力扣第76题「最小覆盖子串」时,我使用了Map<Character, Integer>
来记录字符串中各字符的出现次数。在比较两个字符串各自字符出现次数时,最初我使用了"=="操作符进行比较,但无法通过所有测试用例。后来改用equals()
方法进行比较,最终成功通过了。
问题代码:
if(tMap.containsKey(s.charAt(right)) && sMap.get(s.charAt(right)) == tMap.get(s.charAt(right))){
// 逻辑处理
}
修正后的代码:
if(tMap.containsKey(s.charAt(right)) && sMap.get(s.charAt(right)).equals(tMap.get(s.charAt(right)))){
// 逻辑处理
}
这个问题的根本原因在于Map中存储的值类型是Integer
包装类,而非基本类型int
。
包装类是Java对基本数据类型的封装。当包装类被加载到内存时,JVM会为其创建一个静态内部缓存类,该缓存保存在堆内存中。对于Integer类型,当数值在-128到127之间时,会直接使用缓存中的对象,此时==
和equals()
的效果相同。
但当数值超出这个范围时,由于==
比较的是对象引用而非对象值,就会出现相同数值但引用不同的情况,可能导致程序逻辑错误。
以下是Integer类内部关于缓存的源码:
/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// 获取JVM启动时的参数
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// 缓冲区需要表示负数,所以在设置int整数最大值的情况下,要去除负数和0的个数
h = Math.min(i, Integer.MAX_VALUE - (-low) - 1);
} catch(NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
Java中的自动装箱和自动拆箱机制使得包装类与基本数据类型之间的转换变得非常便捷。自动装箱会利用缓存机制,因为底层调用的是Integer.valueOf(int a)
方法。
重要区别:
Integer.valueOf()
方法:会使用缓存,对于-128到127范围内的数值,返回缓存中的对象Integer.parseInt()
方法:不使用缓存,每次都会创建新的Integer对象示例代码:
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true,使用缓存
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false,超出缓存范围
Integer e = Integer.valueOf(100);
Integer f = Integer.valueOf(100);
System.out.println(e == f); // true,使用缓存
在Java中,除了Float
和Double
之外,其他基本数据类型的包装类都有缓存机制:
基本数据类型 | 包装类型 | 缓存范围 |
---|---|---|
byte | Byte | -128 ~ 127 |
short | Short | -128 ~ 127 |
int | Integer | -128 ~ 127 |
long | Long | -128 ~ 127 |
char | Character | 0 ~ 127 |
boolean | Boolean | true, false |
float | Float | 无缓存 |
double | Double | 无缓存 |
equals()
方法,避免因缓存机制导致的意外行为Java包装类的缓存机制是JVM的一项优化措施,旨在减少小范围整数对象的创建开销。理解这一机制有助于我们:
记住:在比较包装类对象时,使用equals()
方法是最安全的选择!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。