JDK源码学习一--Integer、Long、Float、Double基本数据类的缓存

1.Integer、Long、Float、Double基本数据类

问题来源:今天偶然看到了Integer.valueOf()方法,而查看资料显示【.valueof()是一个静态方法,同时调用几次该方法来创建Integet对象,最终都是调用到同一个Integer实例。】
由于对jdk的api实现不熟悉,所以不明白这些是怎么做到的。因此我编写一个例子进行一下验证:

Integer a = Integer.valueof(10);
Integer b = Integer.valueof(10);
Integer c = null;
c=10;
a=11;

最后我在 c = 10;处打下断点,查看各个对象的id号,发现实例a、b、c三个都是同一个实例id号,因此就表示a、b、c 是同一个对象。
这种结果正好符合资料上面的描述。当我把a=11;重新设置值时,对象a的实例id变成新的id号了,这样就相当于重新实例了一个Integer对象。
这种现象我没有弄明白,按照正常的思维来分析,a=11;这句代码应该只是把Integer实例中的value属性重设一下值,为什么会重新实例一个新的
Integer对象呢?是在没弄明白,所以只好去查看jdk 1.5 API源代码。
打开Integer类,里面的方法让我大开眼界,发现自己和大师级别人物的差距太大了,所以以后要继续好好学习,追随他们,直至超越(低调...)
根据上面的【问题来源】我有一下几个问题需要通过jdk的源码来解答疑惑。
1.为什么调用a、b、c这三个变量调用Integer.valueof()会得到同一个实例?
2.为什么c=10;也会自动变成一个等同于a、b的实例?
3.为什么执行a=11;之后会产生一个新的Ingeter对象?
抱着疑问去看东西,永远是最有效果的。
打开Integer类,就让我看到了一句代码,不得其解。
public static final Class TYPE = (Class) Class.getPrimitiveClass("int");

4.这句代码的意思不是很清楚,也不知道TYPE到底有啥作用,问题是Class.getPrimitiveClass()这个方法我在jdk1.5 api文档里面都没有找到。
这个问题先放下,不影响我对上面三个问题的解答。

问题一解答:
为什么调用Integer.valueof()会得到同一个实例,只好去查找valueof()方法。方法代码如下:

public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache 该处只能缓存-128~127的数据,超出这个范围的就都是新实例化Ingeter对象。
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}



IntegerCache是Integer类的一个成员内部类,代码如下:
public final class Integer extends Number implements Comparable {
… …
private static class IntegerCache {
private IntegerCache(){}

static final Integer cache[] = new Integer[-(-128) + 127 + 1];//静态设置一个存储Integer的数组,就是一个cache
//初始化这个cache,你会发现这个cache里面只缓存了-128~127这个范围的Integer实例。
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Integer(i - 128);
}
}

… …
}

按照源代码的逻辑来推断,只有在数值属于(-128~127)这个范围类的数据,调用Integer.valueof(输入的数值)才会使用缓存中已实例化好的对象。
超出这个范围的数据都是新实例化的对象。接下来就验证这个结论:

Integer e = Integer.valueof(128);
Integer f = Integer.valueof(128);


验证发现:果然e、f的实例号不一样。说明不在(-128~127)范围内的数据调用Integer.valueof()是产生新的实例。


自动装箱与拆箱的功能事实上是编译器来帮您的忙,编译器在编译时期依您所编写的语法,决定是否进行装箱或拆箱动作。在自动装箱时对于值从-128到127之间的值,它们被装箱为Integer对象后,会存在内存中被重用,所以范例4.6中使用==进行比较时,i1 与 i2实际上参考至同一个对象。如果超过了从-128到127之间的值,被装箱后的Integer对象并不会被重用,即相当于每次装箱时都新建一个Integer对象,所以范例4.7使用==进行比较时,i1与i2参考的是不同的对象。所以不要过分依赖自动装箱与拆箱,您还是必须知道基本数据类型与对象的差异。

你可能感兴趣的:(java基础)