📜  Java内部化-解析数字(1)

📅  最后修改于: 2023-12-03 15:32:02.644000             🧑  作者: Mango

Java内部化-解析数字

在Java中,数字类型例如intlongdouble等,本质上是二进制的形式存储的。Java将数字类型内部化,即在内存中复用比较小的数字类型的实例。

内部化的目的是为了节省内存,提升性能。当我们使用类似Integer.valueOf(10)的方法创建数字对象时,如果该数字已经被内部化了,就返回内部对象的引用,否则就创建一个新的对象。这样在程序中频繁使用相同的数字时,内存中就只会保存一份实例,从而减少内存的消耗。

下面我们来看一下Java内部化数字的一些具体实现。

Integer内部化

在Integer内部,通过静态代码块的方式,预先生成了-128到127之间的数字范围内的所有整数实例。

static {
    int low = -128;
    int high = Integer.getInteger("java.lang.Integer.IntegerCache.high", 127);
    final int length = high - low + 1;
    Integer[] cache = new Integer[length];
    int j = low;
    for(int i = 0; i < cache.length; i++)
        cache[i] = new Integer(j++);
    IntegerCache.high = high;

    // valueOf will cache small values, so they must be initialized
    // here or risk not being noticed during autoboxing tests.
    for(int k = 0; k < IntegerCache.cache.length; k++)
        IntegerCache.cache[k] = new Integer(k - 128);
}

可以看到,Java内存中复用的整数实例被存储在一个长度为256的缓存数组中,称之为cache。其中cache数组中前128个元素存储的是-128到0之间的数值,后128个元素存储的是0到127之间的数值,这些数值对应着整型的最小和最大范围。

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[] = new Integer[(high = 128) + 127 + 1];

    private IntegerCache() {}
}

当我们需要获取一个整数实例的时候,可以使用Integer.valueOf(int i)方法,该方法会首先判断需要获取的整数是否在-128到127范围内,如果是,就直接从缓存数组cache中获取对应的实例,否则就新创建一个实例。

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

在Double和Float中,内部化操作是通过sun.misc.Unsafe类来实现的。UnSafe类中有一个方法public native long doubleToRawLongBits(double value),可以将double类型的数值转换为long类型的二进制表示,而该long类型的值可以唯一确定原始的double值。通过将Double和Float的内部化实现细节封装在sun.misc.DoubleConsts和sun.misc.FloatConsts中,我们可以轻松地访问内部化数字。

下面通过具体代码实现来展示一下Double的内部化实现:

// DoubleConsts中维护的double类型常量
public final class DoubleConsts {
    public static final double POSITIVE_INFINITY = 1.0 / 0.0;
    public static final double NEGATIVE_INFINITY = -1.0 / 0.0;
    public static final double NaN = 0.0d / 0.0;
    public static final double MAX_VALUE = 0x1.fffffffffffffP+1023; // 1.7976931348623157e+308
    public static final double MIN_NORMAL = 0x1.0p-1022; // 2.2250738585072014E-308
    public static final double MIN_VALUE = 0x0.0000000000001P-1022; // 4.9e-324
    // ...省略部分代码
}

// Double中的valueOf方法
public static Double valueOf(double d) {
    return new Double(d);
}

// Double中的内部化实现
public static Double valueOf(double d) {
    return new Double(d);
}

// Float中的内部化实现
public static Float valueOf(float f) {
    return new Float(f);
}
总结

Java的内部化技术可以显著提升程序的运行效率和内存使用效率。在Java中,字面量整型、浮点型常量值、常量字符串等常量池内的常量都可以被内部化。熟练掌握Java内部化技术,能够大大提高程序的性能,从而更好地服务于我们的业务需求。