Integer源码分析与高速区间数据缓存

包装类存在的意义

1基本类型与包装类

(1)一切皆对象,但是基本类型却不是对象。
(2)声明方式不同,引用数据类型需要用new关键字来创建,基本数据类型不需要。
(3)存储位置不同,基本数据类型直接存储保存在堆栈中,能高效存取,引用数据类型需要引用指向实例,具体的实列保存在堆中。
(4)引用数据类型的初始值为null,基本数据类型的初始值依其数据类型而定。

2 包装类存在的意义

基本数据类型不是对象,不是Object的子类,不能参与面向对象的开发。在设计到面向对象开发时,就会需要包装类。比较典型的场景,例如hashCode()获取哈希值,或者getClass()获取类等。包装类型可以解决基本数据类型解决不了的事情:泛型类型参数、序列化、类型转换、高频区间数据缓存等。

List<Integer> list = new ArrayList<>();
list.add(1);
-----------------反编译后代码----------------------
List list = new ArrayList();
list.add(Integer.valueOf(1));

Integer源码分析与高速区间数据缓存

1. 类定义

public final class Integer extends Number implements Comparable<Integer>
  • 由final修饰,不能被继承。
  • 实现Comparable接口,可比较,代码中实现compareTo(i)方法。
  • 继承Number类,代码中实现6种数值类型转换方法。Number类实现Serializable接口,表示Integer类可序列化。

2. 属性和常量

public static final int   MIN_VALUE = 0x80000000; // 最小值
public static final int   MAX_VALUE = 0x7fffffff; // 最大值
public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int"); // 标记int包装类
public static final int SIZE = 32; // int二进制位数
public static final int BYTES = SIZE / Byte.SIZE; // 二进制int字节数,JDK8新增

上面是Integer中常量。

private final int value;

value是Integer中唯一的属性,由final修饰,赋值后不能修改。

3. 常用方法

Integer中方法很多是类型转换方法,例如实现Number类的抽象方法(intValue()等),实现compareTo方法。

// 返回保存指定值的Integer对象,默认十进制
public static Integer valueOf(String s)
// 返回Integer对象对应int值
public int intValue()
// 以二进制无符号整数形式返回一个整数的字符串表示。
public static String toBinaryString(int i)
// 获取系统属性中指定名称nm对应值,val为默认值。
public static Integer getInteger(String nm, int val)

public int hashCode() {
    return Integer.hashCode(value);
}
public static int hashCode(int value) {
    return value;
}

特别注意的是,Integer的hashCode值是value变量值!!

JDK8新增了几个聚合函数

public static int sum(int a, int b)
public static int max(int a, int b)
public static int min(int a, int b)

4. Integer高速区间缓存(核心考点)

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

返回int数值的Integer实例。如果不需要特别要求创建新的Integer实例,valueOf()相比于new Integer(i)方法有着更好的空间和时间性能。性能提升是通过缓存常用值实现的。IntegerCache.cache数组中至少缓存[-128,127]范围的Integer实例。

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // high value may be configured by property
        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);
                // Maximum array size is Integer.MAX_VALUE
                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() {}
}

IntegerCache是私有的静态内部类,外部类不能引用该类。类中包含三个final属性,分别是缓存实例对应int值范围low和high,一个Integer数组cache用来存放实例。IntegerCache缓存在首次使用时初始化。

在8中基本数据类型对应的包装类中,除了浮点类型Float和Double类型,其余6个包装类都设置了高速区间数据缓存。比较特殊的是,Integer是唯一可以修改缓存范围的包装类。IntegerCache中high默认值是127,可以设置JVM参数-XX:AutoBoxCacheMax=<size>。缓存数组cache的最大范围是Integer.MAX_VALUE,size值小于等于Integer.MAX_VALUE - 128 - 1,并且必然大于等于127。

对于Integer var = 42,我们知道自动装箱是Java语法糖,实际上底层实现代码是Integer var = Integer.valueOf(42)。使用了valueOf()方法,就用到了IntegerCache缓存。因此,在高速区间数据缓存范围内的值可以通过 == 判断。区间内的值会复用已有对象,区间外的数据会在堆上生成,并不会复用已有的对象。然而,对于包装类的比较,采用equals方法更好一些,保持一致性。

Integer a = 42;
Integer b = 42;
System.out.println(a == b); // true
System.out.println(a.equals(b)); // true

文章结束#

发布了72 篇原创文章 · 获赞 110 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/LIZHONGPING00/article/details/103624441
今日推荐