zoukankan      html  css  js  c++  java
  • Java学习之==>int和Integer的区别和联系

    一、区别

    1、类型

    • int是java中原始八种基本数据类型之一;
    • Integer是一个类,包装整型提供了很多日常的操作;

    2、存储位置和大小

    • 如果作为方法中的局部变量:
      • int是由jvm底层提供,由Java虚拟机规范,int型数据存储在局部变量区,占用一个数据单元(4个字节);
      • Integer型数据存储在Java运行时数据区的堆中,不在使用时可被垃圾回收机制回收;
        • Integer对象占用的存储空间大小:
          • Mark Word:4个字节,标记位;
          • Class对象指针:4字节,指向对应class对象的内存地址;
          • 对齐: 对齐填充字节,按照8个字节填充;
          • 4+4+8 = 16字节;
    • 如果作为类的成员变量,则不管是 int 类型还是 Integer 类型则都是存储在堆中;

    3、使用时字节码的区别

    • int型字节码示例:
      • 定义:int num1 = 32;
      • 字节码: 0: bipush 32;
    • Integer型字节码示例:
      • 定义:Integer num2 = 64;
      • 字节码:
        • 3:bipush 64;
        • 5:invokestatic #20 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

    二、联系

    1、相互转化

    • Integer.valueOf, int -> Integer;
    • Integer.intValue() Integer -> int;
    • 也可以直接相互赋值;

    2、自动拆装箱操作(auto boxing/unboxing)

    • int -> Integer ,装箱;
    • Integer -> int, 拆箱;
    • 注意: 程序中尽量避免无意中的拆装箱操作,尤其是有性能考虑时;

    3、Integer中缓存机制的分析

    public static Integer valueOf(int i) {
      if (i >= Integer.IntegerCache.low && i <= Integer.IntegerCache.high)
        return Integer.IntegerCache.cache[i + (-Integer.IntegerCache.low)];
      return new Integer(i);
    valueOf
    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 Integer.IntegerCache.high >= 127;
      }
    
      private IntegerCache() {}
    }
    IntegerCache

      定义一个 Integer 类型的数据时会调用 Integer 的 valueOf() 方法,通过对以上源码分析发现:调用 valueOf() 方法时会先判断 int 型数据的数值范围,如果在 Integer 的缓存范围内,则调用IntegerCache类,如果不在 Integer 的缓存范围内,则直接 new 一个新的 Integer 对象。

      再看IntegerCache的源码,发现 Integer 缓存范围默认最小值是 -128,获取最大值时先会去读取 JVM 中配置的参数,如果配置了该参数值,则拿这个值和128比较取二者中更大的值作为 Integer 缓存的最大值,如果未配置该参数,则取128作为 Integer的最大值。

      下面我们来些个方法来证明以上分析,代码如下:

    public void integerCache() {
      Integer i1 = 128;
      Integer i2 = 128;
    
      // false
      System.out.println(i1 == i2);
    
      Integer i3 = 127;
      Integer i4 = 127;
    
      // true
      System.out.println(i3 == i4);
    
      Integer i5 = 257;
      Integer i6 = 257;
    
      // false
      System.out.println(i5 == i6);
    }

    运行该方法结果如下:

    127在缓存范围内,而128和257不再缓存范围内。

    我们加上JVM配置 -XX:AutoBoxCacheMax=256,然后把代码改为如下,再次运行该方法

    public void integerCache() {
      Integer i1 = 128;
      Integer i2 = 128;
    
      // false
      System.out.println(i1 == i2);
    
      Integer i3 = 256;
      Integer i4 = 256;
    
      // true
      System.out.println(i3 == i4);
    
      Integer i5 = 257;
      Integer i6 = 257;
    
      // false
      System.out.println(i5 == i6);
    }

    证明配置生效,128和256在缓存范围内,257不再缓存范围内。以上结果证明我们对源码的分析是正确的。

    注意事项:

    • 在做相等判断时,若为基础数据类型则可直接使用==,若为包装类型则需要使用equals;
    • 业务中若使用包装类型,要注意默认值是null,因为基础数据类型的默认值是0容易让大家养成了习惯,这里最易疏忽;

    4、扩展

    • 其他基本数据类型与对应的包装类型是否类似
    • 那么自动拆装箱时是否会使用到缓存机制呢
    • 自动拆装箱时为啥可以做到自动转化?
      • 语法糖
      • 编译支持(字节码)
    • 前面对源码进行了分析,也提到了Integer的缓存最大是127,但是我的系统中会有很多整数的使用,一般范围在1024之内,可以利用缓存吗?
      • -XX:AutoBoxCacheMax=256
    • 既然分析过源码,那么说一下有哪些设计要点?
      • 不可变性
        • 猜测: Integer内部装载的依旧是整数, 而在相互转化时,可以基于intValue()获取int值,那就从intValue()方法追进去,找int的存储;
        • return value;
        • private final int value;
        • 进而可知,Integer对象定义的对象也是不可变的;
        • 好处是保证了基本的信息安全和并发编程中的线程安全;
      • 移植性
        • 在64位操作系统写的代码移植到32位系统上,数据会否发生变化?
        • 在Integer中定义了常量:
          • @Native public static final int SIZE = 32;
          • public static final int BYTES = SIZE / Byte.SIZE;
        • Java语言规范: 无论是32位还是64位,开发者不需要担心位数的问题;
    • 有了Integer还要int干啥? 或者有了int还要Integer干啥?
    • Java号称纯面向对象,为啥搞一批原始类型让人去诟病,面向对象的一点都不纯粹呢?
      • 工程上的考虑,基本数据类型在执行效率和内存使用上提升软件性能,想想Java刚出生的年代,25年前,那会的硬件发展远没有现在这般牛掰,所以性能是工程师及其重视的问题;
      • 其他? 泛型的设计和考虑;
  • 相关阅读:
    316 Remove Duplicate Letters 去除重复字母
    315 Count of Smaller Numbers After Self 计算右侧小于当前元素的个数
    313 Super Ugly Number 超级丑数
    312 Burst Balloons 戳气球
    309 Best Time to Buy and Sell Stock with Cooldown 买股票的最佳时间含冷冻期
    Java 类成员的初始化顺序
    JavaScript 全局
    HTML字符实体
    Java中的toString()方法
    JavaScript 弹窗
  • 原文地址:https://www.cnblogs.com/L-Test/p/11440827.html
Copyright © 2011-2022 走看看