经过昨天的学习,我们了解了关于"=="的一些知识:
== 的作用:
基本类型:比较的就是值是否相同
引用类型:比较的就是地址值是否相同
根据,昨天的学习,我们会觉得 a和b是引用类型,那么 a==b 肯定是false呀,但是结果如下:
诶?这是为什么呢?明明a和b是两个不同的对象,但是为什么a==b是true呢?解释如下:
Integer内部使用了享元模式的设计,什么是享元模式呢?
享元模式是一种结构型设计模式,它旨在通过共享相似对象的部分状态来节省内存和提高性能。在 Java 中,享元模式通常通过使用工厂模式来实现。
在享元模式中,有两种类型的对象:内部状态和外部状态。内部状态是不会改变的,可以被多个对象共享。外部状态是会变化的,每个对象都具有自己的外部状态。
下面是一个简单的 Java 代码示例,展示了如何使用享元模式:
// 创建一个接口定义享元对象的操作
interface Flyweight {
void operation();
}
// 创建具体的享元对象实现接口
class ConcreteFlyweight implements Flyweight {
private String intrinsicState;
public ConcreteFlyweight(String intrinsicState) {
this.intrinsicState = intrinsicState;
}
public void operation() {
System.out.println("具体享元对象的操作,内部状态为:" + intrinsicState);
}
}
// 创建享元工厂类用于创建和管理享元对象
class FlyweightFactory {
private Map<String, Flyweight> flyweights = new HashMap<>();
public Flyweight getFlyweight(String key) {
if (flyweights.containsKey(key)) {
return flyweights.get(key);
} else {
Flyweight flyweight = new ConcreteFlyweight(key);
flyweights.put(key, flyweight);
return flyweight;
}
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
FlyweightFactory factory = new FlyweightFactory();
// 获取享元对象并调用操作
Flyweight fw1 = factory.getFlyweight("key1");
fw1.operation();
Flyweight fw2 = factory.getFlyweight("key2");
fw2.operation();
Flyweight fw3 = factory.getFlyweight("key1"); // 已存在的享元对象
fw3.operation();
}
}
在上面的示例中,ConcreteFlyweight
类表示具体的享元对象,FlyweightFactory
类充当享元工厂。客户端通过工厂类获取享元对象,并调用其操作。
通过使用享元模式,可以避免创建大量相似的对象,节省内存空间,并提高性能。
Integer中的享元模式,针对-128到127之间的数字做了一个缓存,使用Integer a = 100这个方式赋值的时候,java默认会通过valueOf这个方法对100这个数字进行一个装箱操作,从而触发了缓存机制,使得a和b指向了同一个Integer的内存地址。
在 Java 中,整型包装类 java.lang.Integer
使用了享元模式来缓存和重用整数对象。这个缓存的整数范围是 -128 到 127。
java.lang.Integer
类有一个静态内部类 IntegerCache
,它作为整数缓存的实现。下面是 IntegerCache
类的源代码:
private static class IntegerCache {
static final int low = -128; // 缓存的最小整数值
static final int high; // 缓存的最大整数值,默认是 127
static final Integer cache[]; // 整数对象缓存数组
static {
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);
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
}
catch( NumberFormatException nfe) {
// 如果解析整数失败,使用默认值127
throw new RuntimeException("Illegal value for property 'java.lang.Integer.IntegerCache.high': " + integerCacheHighPropValue);
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// 如果设置了 `-XX:AutoBoxCacheMax=n` JVM 参数,可以增加缓存容量
if (high >= 127) {
int size = Math.min(8192, high - low + 1);
Integer[] newCache = new Integer[size];
System.arraycopy(cache, 0, newCache, 0, cache.length);
cache = newCache;
}
// 在需要的整数范围内,其他整数将不会被缓存,会通过 new Integer() 创建新的对象
}
private IntegerCache() {}
}
从上面的代码可以看出,IntegerCache
类首先根据系统属性 java.lang.Integer.IntegerCache.high
来确定缓存的最大整数值。如果没有设置该系统属性或解析失败,将使用默认值 127。然后,根据最小整数值和最大整数值初始化一个整数对象缓存数组。
缓存数组的大小默认为 high - low + 1
,即缓存范围内的整数个数。如果缓存范围超过了 127
,也就是超过了默认的缓存容量,会根据 -XX:AutoBoxCacheMax=n
JVM 参数来增加缓存容量。
通过缓存数组,Integer
类能够重用并共享整数对象,避免通过 new Integer()
创建新的对象。
山的那边会是海吗?