包装类缓存对象
在 Java 中,包装类(如 Integer
、Long
、Character
等)为了提高性能和节省内存,对一定范围内的值进行了缓存。这种缓存机制使得在某些情况下,相同的值会返回相同的对象,而不是创建新的对象。
1. 包装类的缓存机制
- 缓存范围:
Integer
:默认缓存-128
到127
之间的值。Long
:默认缓存-128
到127
之间的值。Character
:缓存0
到127
之间的值。Byte
:缓存所有可能的值(-128
到127
)。Short
:默认缓存-128
到127
之间的值。Boolean
:缓存true
和false
。
- 缓存实现:
- 包装类在内部维护了一个缓存数组(如
IntegerCache
),在缓存范围内的值会直接从缓存中返回对象。
- 包装类在内部维护了一个缓存数组(如
2. 示例:Integer
的缓存机制
- 缓存范围内的值:
- 在
-128
到127
之间的值会返回相同的对象。
- 在
- 缓存范围外的值:
- 超出缓存范围的值会创建新的对象。
代码示例:
public class IntegerCacheExample {
public static void main(String[] args) {
Integer a = 127; // 使用缓存
Integer b = 127; // 使用缓存
System.out.println(a == b); // true
Integer c = 128; // 超出缓存范围,创建新对象
Integer d = 128; // 超出缓存范围,创建新对象
System.out.println(c == d); // false
}
}
输出:
true
false
3. 修改 Integer
的缓存范围
- 通过 JVM 参数调整缓存范围:
- 可以通过
-XX:AutoBoxCacheMax=<size>
参数调整Integer
的缓存上限。
- 可以通过
- 示例:
- 将缓存范围扩大到
-128
到200
。
- 将缓存范围扩大到
运行命令:
java -XX:AutoBoxCacheMax=200 IntegerCacheExample
代码示例:
public class IntegerCacheExample {
public static void main(String[] args) {
Integer a = 200; // 使用缓存
Integer b = 200; // 使用缓存
System.out.println(a == b); // true
}
}
输出:
true
4. 其他包装类的缓存机制
Long
缓存机制:- 默认缓存
-128
到127
之间的值。
- 默认缓存
代码示例:
public class LongCacheExample {
public static void main(String[] args) {
Long a = 127L; // 使用缓存
Long b = 127L; // 使用缓存
System.out.println(a == b); // true
Long c = 128L; // 超出缓存范围,创建新对象
Long d = 128L; // 超出缓存范围,创建新对象
System.out.println(c == d); // false
}
}
输出:
true
false
Character
缓存机制:- 缓存
0
到127
之间的值。
- 缓存
代码示例:
public class CharacterCacheExample {
public static void main(String[] args) {
Character a = 127; // 使用缓存
Character b = 127; // 使用缓存
System.out.println(a == b); // true
Character c = 128; // 超出缓存范围,创建新对象
Character d = 128; // 超出缓存范围,创建新对象
System.out.println(c == d); // false
}
}
输出:
true
false
5. 缓存机制的意义
- 性能优化:
- 缓存机制避免了频繁创建和销毁对象,提高了性能。
- 节省内存:
- 对于常用的小范围值,直接使用缓存对象可以减少内存占用。
- 注意事项:
- 在比较包装类对象时,应使用
equals()
方法而不是==
,因为==
比较的是对象的引用,而不是值。
- 在比较包装类对象时,应使用
代码示例:
public class WrapperComparison {
public static void main(String[] args) {
Integer a = 128;
Integer b = 128;
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true
}
}
输出:
false
true
6. 自定义包装类的缓存
- 如果需要实现自定义包装类的缓存机制,可以参考
IntegerCache
的实现方式。 - 示例:自定义一个
MyInteger
类,并实现缓存机制。
代码示例:
public class MyInteger {
private int value;
private static final MyInteger[] cache = new MyInteger[256];
static {
for (int i = 0; i < cache.length; i++) {
cache[i] = new MyInteger(i - 128);
}
}
private MyInteger(int value) {
this.value = value;
}
public static MyInteger valueOf(int value) {
if (value >= -128 && value <= 127) {
return cache[value + 128];
}
return new MyInteger(value);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof MyInteger) {
return this.value == ((MyInteger) obj).value;
}
return false;
}
@Override
public String toString() {
return Integer.toString(value);
}
}
public class MyIntegerCacheExample {
public static void main(String[] args) {
MyInteger a = MyInteger.valueOf(127); // 使用缓存
MyInteger b = MyInteger.valueOf(127); // 使用缓存
System.out.println(a == b); // true
MyInteger c = MyInteger.valueOf(128); // 超出缓存范围,创建新对象
MyInteger d = MyInteger.valueOf(128); // 超出缓存范围,创建新对象
System.out.println(c == d); // false
}
}
输出:
true
false
总结
包装类的缓存机制是 Java 中一种重要的性能优化手段,适用于常用的小范围值。在使用包装类时,应注意以下几点:
- 了解缓存范围,避免不必要的对象创建。
- 在比较包装类对象时,使用
equals()
方法而不是==
。 - 可以通过 JVM 参数调整
Integer
的缓存范围。 - 如果需要,可以参考包装类的缓存机制实现自定义缓存。