Java-07:int和Integer有什么区别?

7、int 和 Integer有什么区别?

1、数据类型

iint是基本数据类型,保存在栈中;Integer是引用类型,在堆中申请内存存放数据,在栈里申明引用指向堆中的内存地址。

基本数据类型在栈中怎么存储?

int a = 10;
int b = 10;

JVM有一个局部变量表用来保存引用,如上,建立引用a和引用b,再申请两块内存来存放数据,由引用a和引用b指向它们的内存地址。在Java中, "=="符号是用于比较引用的值,这话没毛病。

那引用类型在堆中怎么存储?

Java普通对象在HotSpot虚拟机Java堆中的内存布局大致可分为3个区域:对象头(Header)、实例数据(Instance)和对齐填充(Padding)。

对象头分为两部分:

  • Mark Word:用于存储对象自身的运行时数据,长度为32bit或者64bit,同时Mark Word被设计成一个有着动态定义的数据结构,以便在极小的空间内存储尽量多的数据,会根据对象的状态复用自己的存储空间 。
  • 类型指针:记录指向它的类型元数据的指针,如果是数组对象,还需要记录它的数组长度。

实例数据:

对象存储有效信息的位置

对其填充:

HotSpot虚拟机要求对象大小必须是8字节的整数倍; So,我们需要把它补齐。

2、Integer和int的关系

Integer是int的包装类,java有8个基本数据类型:byte、int、long、float、double、boolean、char,同时也会有8个包装类。

我们将int转Integer就是装箱,从Integer转int就是拆箱

装箱/拆箱又分为自动和手动,下面是例子:

public class MainTest {
    public static void main(String[] args) {
        // 手动装箱
        Integer c = new Integer(10);
        // 自动装箱
        Integer d = 10;

        // 手动拆箱
        int e = c.intValue();
        // 自动拆箱
        int f = c;
    }
}

我们将上述的源代码进行编译后,使用jd-gui工具进行反编译,得到如下结果:

public class MainTest
{
  public static void main(String[] paramArrayOfString)
  {
    Integer localInteger1 = new Integer(10);
    
    Integer localInteger2 = Integer.valueOf(10);
    
    int i = localInteger1.intValue();
    
    int j = localInteger1.intValue();
  }
}

我们会得到如下结论:

自动装箱时编译器会调用valueOf(XX)的方法来量基本数据类型转化为对象;

自动拆箱时编译器会调用intValue、doubleValue等方法将对象装换到基本数据类型。

3、缓存池

valueOf(XX)内部是由玄机的,它有一个缓存池,我们先来看下IntegerCache内部类:

    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内部的组成不多,我们来看下:

定义了缓存的下限;

static final int low = -128;

定义缓存的上限引用,没有赋值;

static final int high;

定义缓存存放的数据,我们可以看到,缓存就是一个普通的Integer数组;

static final Integer cache[];

我们能看到静态初始语句由如下功能:

  • 先给缓存的上限(high)赋值初始值,但这个值可以被后续读取到配置属性覆盖
  • 从JVM配置中获取缓存上限的值(integerCacheHighPropValue)
  • 选择上限值,从integerCacheHighPropValue,high,Integer.MAX_VALUE - (-low) -1三者选择
  • h+(-low)+1不能超过Integer.MAX_VALUE
  • 初始化Integer数组
  • 给Integer数组赋初始值
        static {
            // 1. 先给缓存的上限(high)赋值初始值,但这个值可以被后续读取到配置属性覆盖
            int h = 127;
            // 2. 从JVM配置中获取缓存上限的值
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
       // 3. 选择上限值,从integerCacheHighPropValue,h,Integer.MAX_VALUE - (-low) -1三者选择
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // h+(-low)+1不能超过Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                }
            }
            high = h;
			//  4. 初始化Integer数组
            cache = new Integer[(high - low) + 1];
            int j = low;
            // 5. 给Integer数组赋初始值
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
			// 6. 断言判断缓存的上限
            assert IntegerCache.high >= 127;
        }

我们再来看下valueOf(XX)方法,我们就明白了;

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

总结来说: Integer类型的缓存就是一个Integer数组,下限的值为-128(写死),上限的值默认为127,不过我们可以通过配置JVM参数来修改它,只有调用valueOf(XX)方法才能会经过缓存池,也就是手动调用valueOf(XX)或者自动装箱。

缓存上限值是根据需要调整的,JVM 提供了如下参数:

-XX:AutoBoxCacheMax=N
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页