2021-08-02

int与Integer

每日一练:天道酬勤
问:为什么java需要基本数据类型的包装类?
答:Java是一个面向对象的编程语言,基本类型并不具有对象的特质(封装继承多态),为了让基本类型也具有对象的特征,就出现了包装类型(如使用集合类型Collection时就一定要使用包装类型而非基本类型),它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。
问:基本数据类型转包装类型有哪些?
答:
基本类型包装类包装类缓存取值范围
booleanBoolean使用静态 final 定义
charCharacter缓存区 0~127
intInteger缓存区 -128~127
byteByte缓存区 -128~127
shortShort缓存区 -128~127
longLong缓存区 -128~127
floatFloat没有缓存
doubleDouble没有缓存
Number是所有数字包装类的父类
问:自动装箱、自动拆箱是什么?举个栗子
答:

装箱:将基础数据类型包装成对应的包装类

//构造方法
Integer int1=new Integer(1);
//valueOf()实际也是通过构造方法 
Integer int2=Integer.valueOf(1);
//自动装箱(实际上编译时会调用 Integer的ValueOf封装
Integer int3=1;

拆箱:将包装类转为对应的基础数据类型

// 手动拆箱方式
Integer int3=1;
int int4=int3.intValue();
//自动拆箱(实质:在编译的时候调用用intValue())
Integer int3=1;
int int5=int3;

自动拆箱时如果包装类是null,那么会抛出NPE

问:int和Interger的区别?
答:
  • Integer是int的包装类,int则是java的一种基本数据类型
  • Integer变量必须实例化后才能使用,而int变量不需要
  • Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值
  • Integer的默认值是null,int的默认值是0
问:什么时候用包装类,什么时候用基本类型?
答:1. 在pojo类中定义的属性用包装类2. 在rpc方法中定义参数和返回值的类型用包装类3. 定义局部变量用基本类型
练习题

由于Integer变量实际上是对一个Integer对象的引用,所以两个通过new生成的Integer变量永远是不相等的(因为new生成的是两个对象,其内存地址不同)

Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.print(i == j);//false

Integer变量和int变量比较时,只要两个变量的值是向等的,则结果为true(因为包装类Integer和基本数据类型int比较时,java会自动拆包装为int,然后进行比较,实际上就变为两个int变量的比较)

Integer i = new Integer(100);
int j = 100System.out.print(i == j); //true

非new生成的Integer变量和new Integer()生成的变量比较时,结果为false。(因为 ①当变量值在-128~127之间时,非new生成的Integer变量指向的是java常量池中的对象,而new Integer()生成的变量指向堆中新建的对象,两者在内存中的地址不同;②当变量值在-128~127之间时,非new生成Integer变量时,java API中最终会按照new Integer(i)进行处理(参考下面第4条),最终两个Interger的地址同样是不相同的)

Integer i = new Integer(100);
Integer j = 100;
System.out.print(i == j); //false

对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false

Integer i = 100;
Integer j = 100;
System.out.print(i == j);//true
Integer i = 128;
Integer j = 128;
System.out.print(i == j); //false

对于第4条的原因:
java在编译Integer i = 100 ;时,会翻译成为Integer i = Integer.valueOf(100);,而java API中对Integer类型的valueOf的定义如下:

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

java对于-128到127之间的数,会进行缓存,Integer i = 127时,会将127进行缓存,下次再写Integer j = 127时,就会直接从缓存中取,就不会new了

解析
new Integer(100) 与 Integer.valueOf(100) 的区别在于:
  • new Integer(100) 每次都会新建一个对象;
  • java在编译Integer i = 100 ;时,会翻译成为Integer i = Integer.valueOf(100);而java API中对Integer类型的valueOf的定义如下:在 Java 8 中,Integer 缓存池的大小默认为 -128~127。
// 根据JLS的要求,缓存以支持-128和127(包括)之间的值的自动装箱。
// 缓存在首次使用时初始化。
// 缓存的大小可以由{@code -XX:AutoBoxCacheMax = <size>}选项控制。
// 在JVM初始化期间,可以设置java.lang.Integer.IntegerCache.high属性并将其保存在私有系统属性sun.misc.VM类。
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;
}
Integer.valueOf(100) 会使用缓存池中的对象,多次调用会取得同一个对象的引用。所以这三个题的答案也昭然若揭。
其中Integer缓冲池 IntegerCache 是 Integer 类的一个私有静态内部类,其中关键部分是static final Integer cache[];,即它内部保存了Integer类型的数组,用以缓存值在 IntegerCache.low ~ IntegerCache.high 之间的Integer对象。
为什么设计这个缓存?
实践发现,大部分数据操作都是集中在有限的、较小的数值范围。所以在Java 5 中增加了静态工厂方法 valueOf(),在调用它的时候利用缓存机制,这样不用反复new 值相同的Integer对象,减少了内存占用。
基本类型对应的缓冲池如下:
  • boolean values true and false
  • all byte values
  • short values between -128 and 127
  • int values between -128 and 127
  • char in the range \u0000 to \u007F
在使用这些基本类型对应的包装类型时,如果该数值范围在缓冲池范围内,就可以直接使用缓冲池中的对象。
这是代码的开头的注释
  • // 缓存在首次使用时初始化
  • // 缓存的大小可以由{@code -XX:AutoBoxCacheMax = }选项控制。
  • // 在VM初始化期间,可以设置java.lang.Integer.IntegerCache.high属性并将其保存在私有系统属性sun.misc.VM类。
在 jdk 1.8 所有的数值类缓冲池中,Integer 的缓冲池 IntegerCache 很特殊,这个缓冲池的下界是 - 128,上界默认是 127,但是这个上界是可调的,在启动 jvm 的时候,通过-XX:AutoBoxCacheMax = ; 来指定这个缓冲池的大小,该选项在 JVM 初始化的时候会设定一个名为 java.lang.IntegerCache.high 系统属性,然后 IntegerCache 初始化的时候就会读取该系统属性来决定上界。

欢迎指正~
参考:
https://blog.youkuaiyun.com/darlingwood2013/article/details/96969339
https://www.cnblogs.com/guodongdidi/p/6953217.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值