八种基本类型和常量池


Java语言提供了八种基本类型。 整数类型 byte 8位、short 16位、int 32位和 long 64位,以及浮点类型 float 32位和 double 64位,无符号char 16位和boolean 。

对于存储 boolean 数组的字节码,Java 虚拟机需保证实际存入的值是整数 1 或者 0。 尽管他们的默认值看起来不一样,但在内存中都是 0。在这些基本类型中,boolean 和 char 是唯二的无符号类型。

一、自动装箱与拆箱

在八种包装类型中,每一种包装类型都提供了两个方法:

静态方法valueOf(基本类型):将给定的基本类型转换成对应的包装类型;

实例方法xxxValue():将具体的包装类型对象转换成基本类型; 下面我们以int和Integer为例,说明Java中自动装箱与自动拆箱的实现机制。看如下代码:

//code1
public class Test {
    public static void main(String[] args) {
        Integer  a1 = 1;
        int a2 = a1;
    }
}

使用反编译工具JD-GUI,将生成的Class文件在反编译为Java文件

//code2
public class Test {
  public static void main(String[] args) {
    Integer a1 = Integer.valueOf(1);
    int a2 = a1.intValue();
  }
}

可以看到经过javac编译之后,code1的代码被转换成了code2,实际运行时,虚拟机运行的就是code2的代码。也就是说,虚拟机根本不知道有自动拆箱和自动装箱这回事;在将Java源文件编译为class文件的过程中,javac编译器在自动装箱的时候,调用了Integer.valueOf()方法,在自动拆箱时,又调用了intValue()方法。

实现总结:其实自动装箱和自动封箱是编译器为我们提供的一颗语法糖。在自动装箱时,编译器调用包装类型的valueOf()方法;在自动拆箱时,编译器调用了相应的xxxValue()方法。

二、基本类型缓存(常量池)

以Integer源码为例

 /**
  * 首先会判断i是否在[IntegerCache.low,Integer.high]之间
  * 如果是,直接返回Integer.cache中相应的元素
  * 否则,调用构造方法,创建一个新的Integer对象
  */
 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);
 }

/**
  * 静态内部类,缓存了从[low,high]对应的Integer对象
  * low -128这个值不会被改变
  * high 默认是127,可以改变,最大不超过:Integer.MAX_VALUE - (-low) -1
  * cache 保存从[low,high]对象的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) {
            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);
        }
        high = h;
 
        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
    }
 
    private IntegerCache() {}
}

重点是静态内部类IntegerCache ,它是用来缓存数据的。它有一个数组,里面保存的是连续的Integer对象。cache[low,high] 默认是[-128, 127]。

调用valueOf(inti)方法时,首先判断i是否在[low,high]之间,如果是,则复用Integer.cache[i-low]。比如,如果Integer.valueOf(3),直接返回Integer.cache[131];如果i不在这个范围,则调用构造方法,构造出一个新的Integer对象。默认情况下,在使用自动装箱时,VM会复用[-128,127]之间的Integer对象。

Integer a1 = 1;
Integer a2 = 1;
Integer a3 = new Integer(1);
Integer a4 = 200;
Integer a5 = 200;
System.out.println(a1 == a2);//true,因为a1和a2是同一个对象,都是Integer.cache[129]
System.out.println(a1 == a3);//false,a3构造了一个新的对象,不同于a1,a2
System.out.println(a4 == a5);//false,200超出了默认high值

而String类型可以通过public native String intern() 来完成这个操作。JDK 1.7后,intern方法还是会先去查询常量池中是否有已经存在,如果存在,则返回常量池中的引用,这一点与之前没有区别,区别在于,如果在常量池找不到对应的字符串,则不会再将字符串拷贝到常量池,而只是在常量池中生成一个对原字符串的引用。

参考链接:
[http://www.h5551.com/2018/04/23/javase2/](http://www.h5551.com/2018/04/23/javase2/)

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值