Integer的内部学习:
目录
学习内容:
- Integer自动装箱和拆箱的内部学习
- 静态代码块的深层
- 缓存区域的原理
- 缓存为什么用内部类去写
过程:
Integer自动装箱和拆箱的内部学习
理解自动装箱
当基本数据类型处于需要对象的环境中,就会自动触发装箱机制,也就是说会自动把基本数据类型转换为包装类对象。
底层:触发自动装箱机制的时候,会默认调用valueOf(xxx x)这个静态方法来实现。
(1)提出问题
public static void main(String[] args) {
Integer a = 80;
Integer b = 80;
Integer c = 150;
Integer d = 150;
System.out.println(a == b);
System.out.println(c == d);
}
运行结果:
问题的提出:为什么对象指代的值是相同的,为什么打印的两个结果不同呢?
(2)查找源码
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
要对此代码进行理解就需要了解IntegerCache
(3)查找IntegerCache并对其理解
其中重要的几行代码的理解:
static final int low = -128; //缓存下届并不可改变,只能更改上届。
int h = 127;//h值,自动缓存区间设置为[-128,N]。区间的下界是固定 。
i = Math.max(i, 127);// 取较大的作为上界,但又不能大于Integer的边界MAX_VALUE。
(4)回到第(2)步进行理解
在Integer类中其实存在名叫Cache机制,它是一个常量,存在于Java的方法区中,当我们给定的整数在[-128,127]之间的话,那么会直接从cache中返回对应的Integer类的引用(或者说地址),如果整数的大小不在这个范围内的话,那么valueof()方法会新new一个Integer类型的对象,并返回。
(5)总结
当对象指代的值大于127,每一次返回的包装类型的地址都是不一样的。
理解自动拆箱
当包装类型处于需要基本数据类型的环境中,就会自动触发拆箱机制,也就是说会自动把包装对象转换为基本数据类型。
底层:触发自动拆箱机智的时候,会自动调用xxxValue()这个成员方法
Integer num = 100;
int num1 = num;
执行上面的代码时由于num为包装类型,而num1为基本数据类型,所以会进行自动拆箱,将包装类型转变为基本数据类型。其底层使用的方法是intValue()方法,具体内容如下:
public int intValue() {
return value;
}
静态代码块的执行学习
在代码中含有静态代码块时,我们经常碰到的就是代码块、静态方法、构造方法的执行顺序的问题。
我们通过例子来进行学习子类与父类静态代码块的执行顺序。
package Test2;
public class TestDemo7 extends Test{
static {
System.out.println("子类静态代码块!");
}
{
System.out.println("子类代码块!");
}
public TestDemo7(){
super();
System.out.println("子类构造!");
}
public static void main(String[] args) {
TestDemo7 test = new TestDemo7();
}
}
// 父类
class Test {
public Test(){
System.out.println("父类构造!");
}
{
System.out.println("父类代码块!");
}
static {
System.out.println("父类静态代码块!");
}
}
执行结果:
运用jclasslib生成的信息中的方法,可以看出执行的顺序是–>main–>。
通过分析得出结论: 加载顺序:父类静态代码块>子类静态代码块>main方法
缓存区域的理解
1.什么是缓存
1、Cache是高速缓冲存储器 一种特殊的存储器子系统,其中复制了频繁使用的数据以利于快速访问
2、凡是位于速度相差较大的两种硬件/软件之间的,用于协调两者数据传输速度差异的结构,均可称之为 Cache
2.什么是缓存区域
我们在编写代码的过程中有些数据,数据量小,但是访问十分频繁,针对这种场景,需要将数据放到缓存区域中,以提升系统的访问效率,减少无谓的数据库访问(数据库访问占用数据库连接,同时网络消耗比较大)。
3.缓存区域的好处
将程序或系统经常要调用的对象存在内存中,以便其使用时可以快速调用,不必再去创建新的重复的实例。这样做可以减少系统开销,提高系统效率。一般的用法就是把数据从数据库读到内存,然后之后的数据访问都从内存来读,从而减少对数据库的读取次数来提高效率。
Integer类里为什么实现内部缓存
我们知道在java中创建的新实例需要占用堆中的一些内存空间,因此创建新对象始终是一个昂贵的过程。因此为了避免这种昂贵的对象创建过程,许多框架会以不同的方式进行资源池化。
包装类在java中是不可变的,所以,像字符串池一样,他们也可以拥有自己的"字符串池"(抽象)。JDK提供的包装类也以实例池的形式提供它,即每个包装类以缓存的形式存储自己类型的常用实例列表,并且在需要时,可以在代码中使用它们。它有助于在程序运行时节省大量的字节。
在Integer.java类中有一个内部类,即IntegerCache
IntegerCache代码:
private static class IntegerCache
{
private IntegerCache(){}
static final Integer cache[] = new Integer[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Integer(i - 128);
}
}
valueOf()方法里是这样的:
public static Integer valueOf(int i)
{
final int offset = 128;
if (i >= -128 && i <= 127) // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
IntegerCache是静态内部类,只有在第一次使用时才会被初始化。所以在第一次,由于缓存创建,时间可能会更长,之后不会花费更多时间。但是,实际的好处是内存重用。