Java基础之基本数据类型封装类的缓存

巨人的肩膀:https://blog.csdn.net/hnjcxy/article/details/123787209
1、Java中基本数据类型byte、short、char、int、long、float、double、boolean有对应的封装类型:Byte、Short、Character、Integer、long、Float、Double,Boolean其中Byte、Short、Character、Integer、Long、Boolean都实现了常量池缓存。Byte、Short、Character、Integer、Long通过静态内部Cache类来实现一定范围(下面列出缓存范围)内的数据缓存,而Boolean通过两个静态常量TRUE、FALSE来实现数据缓存。

  • Byte类缓存范围:[-128,127] 共256个值。
  • Short类缓存范围:[-128,127] 共256个值。
  • Character类缓存范围:[0,127] 共128个值。
  • Integer类默认缓存范围:[-128,127] 共256个值,可以通过修改VM参数-XX:AutoBoxCacheMax=200 即可修改缓存上限到200
  • Long类缓存范围:[-128,127] 共256个值。
  • Boolean类就缓存两个值:true、false。
2、装箱和拆箱过程:
装箱:调用封装类 valueOf(x) 方法;
拆箱:调用封装类的 xxValue() 方法。

3、测试
测试前说明:
==对于基本数据类型和对象的比较含义是不同的。对于基本数据类型:“==” 比较的是基本数据类型的数值;对于对象:“==” 比较的是对象在内存中的内存地址。
byte、short、char类型计算后会自动转成整型类型int。

(1)Byte

    static void testByte(){
        System.out.println("Byte类型:");
        Byte i1 = 127;
        Byte i2 = 127;
        Byte i3 = 0;
        Byte i4 = new Byte("127");
        Byte i5 = new Byte("127");
        Byte i6 = new Byte("0");
 
        System.out.println("i1=i2 " + (i1 == i2));  //true 因为数值在[-128,127]的范围内,使用常量池缓存中的127
 
        System.out.println("i1=i4 " + (i1 == i4)); //false 因为i1指向常量池Byte对象127,i4指向堆中Byte对象127
 
        System.out.println("i4=i5 " + (i4 == i5)); //false 因为i4和i5是堆中两个对象
 
        //因为 i5+i6 做算数运算+时,会自动拆箱再做加法,即拆箱后的基本数据类型byte做加法运算,
        //计算结果是整型的127,所以最终是基本数据类型的值作比较;(byte、short、char类型计算后会自动转成整型类型int)
        System.out.println("127=i5+i6 " + (127 == i5 + i6)); //true
        System.out.println("byte计算后,转换类型为:"+ myGetType(i5 + i6));  // int
 
        //因为 i2+i3 做算数运算+时,会自动拆箱再做加法,即拆箱后的基本数据类型byte做加法运算,计算结果是整型的127;
        // i1与基本数据类型127比较的时候也会自动拆箱,所以最终是基本数据类型的值作比较
        System.out.println("i1=i2+i3 " + (i1 == i2 + i3)); //true
 
        //因为 i2+i3 做算数运算+时,会自动拆箱再做加法,即拆箱后的基本数据类型byte做加法运算,计算结果是整型的127;
        // i4与基本数据类型127比较的时候也会自动拆箱,所以最终是基本数据类型的值作比较
        System.out.println("i4=i5+i6 " + (i4 == i5 + i6)); //true
 
        /* Byte类中有缓存静态内部类ByteCache;缓存范围:-128~127,共256(cache.length)个值
        private static class ByteCache {
            private ByteCache(){}
            static final Byte cache[] = new Byte[-(-128) + 127 + 1];
            static {
                for(int i = 0; i < cache.length; i++)
                    cache[i] = new Byte((byte)(i - 128));
            }
        }
         */
    }

(2)Short

    static void testShort(){
        System.out.println("Short类型:");
        Short i1 = 127;
        Short i2 = 127;
        Short i3 = 0;
        Short i4 = new Short("127");
        Short i5 = new Short("127");
        Short i6 = new Short("0");
        Short i1New = 128;
        Short i2New = 128;
 
        System.out.println("i1=i2 " + (i1 == i2));  //true 因为数值在[-128,127]的范围内,使用常量池缓存中的127
 
        System.out.println("i1New=i2New " + (i1New == i2New));  //false 超过缓存范围,创建新对象了
 
        System.out.println("i1=i4 " + (i1 == i4)); //false 因为i1指向常量池对象127,i4指向堆中对象127
 
        System.out.println("i4=i5 " + (i4 == i5)); //false 因为i4和i5是堆中两个对象
 
        //因为 i5+i6 做算数运算+时,会自动拆箱再做加法,即拆箱后的基本数据类型short做加法运算,
        //计算结果是整型的127,所以最终是基本数据类型的值作比较;(byte、short、char类型计算后会自动转成整型类型int)
        System.out.println("127=i5+i6 " + (127 == i5 + i6)); //true
        System.out.println("short计算后,转换类型为:"+ myGetType(i5 + i6));  // int
 
        //因为 i2+i3 做算数运算+时,会自动拆箱再做加法,即拆箱后的基本数据类型short做加法运算,计算结果是整型的127;
        // i1与基本数据类型127比较的时候也会自动拆箱,所以最终是基本数据类型的值作比较
        System.out.println("i1=i2+i3 " + (i1 == i2 + i3)); //true
 
        //因为 i2+i3 做算数运算+时,会自动拆箱再做加法,即拆箱后的基本数据类型short做加法运算,计算结果是整型的127;
        // i4与基本数据类型127比较的时候也会自动拆箱,所以最终是基本数据类型的值作比较
        System.out.println("i4=i5+i6 " + (i4 == i5 + i6)); //true
 
        /* Short类中有缓存静态内部类ShortCache;缓存范围:-128~127,共256(cache.length)个值
        private static class ShortCache {
            private ShortCache(){}
            static final Short cache[] = new Short[-(-128) + 127 + 1];
            static {
                for(int i = 0; i < cache.length; i++)
                    cache[i] = new Short((short)(i - 128));
            }
        }
         */
    }

(3)Character

    static void testChar(){
        System.out.println("Character类型:");
        Character i1New72 = 72;
        Character i1 = 40; //表示字符'('
        Character i2 = 40;
        Character i3 = 32;
        Character i4 = new Character('(');//字符'('的十进制码点值是40
        Character i4New72 = new Character('H');//字符'H'的十进制码点值是72
        Character i5 = new Character('(');
        Character i6 = new Character(' '); //空格的十进制码点值是32
        Character i1New = 128;
        Character i2New = 128;
        Character i1New1 = 127;
        Character i2New2 = 127;
 
        System.out.println("i1=i2 " + (i1 == i2));  //true 因为数值在[0,127]的范围内,使用常量池缓存中的40
 
        System.out.println("i1New=i2New " + (i1New == i2New));  //false 超过缓存范围,创建新对象了
 
        System.out.println("i1New1=i2New2 " + (i1New1 == i2New2));  //true 没有超过缓存范围,使用常量池缓存中的值
 
        System.out.println("i1=i4 " + (i1 == i4)); //false 因为i1指向常量池Character对象40,i4指向堆中Character对象40
 
        System.out.println("i4=i5 " + (i4 == i5)); //false 因为i4和i5是堆中两个对象
 
        //因为 i5+i6 做算数运算+时,会自动拆箱再做加法,即拆箱后的基本数据类型char做加法运算,
        //计算结果是整型的72,所以最终是基本数据类型的值作比较;(byte、short、char类型计算后会自动转成整型类型int)
        System.out.println("72=i5+i6 " + (72 == i5 + i6) +" 因为:i5+i6= " + (i5 + i6)); //true
        System.out.println("char计算后,转换类型为:"+ myGetType(i5 + i6));  // int
 
        //因为 i2+i3 做算数运算+时,会自动拆箱再做加法,即拆箱后的基本数据类型char做加法运算,计算结果是整型的72;
        // i1New72与基本数据类型72比较的时候也会自动拆箱,所以最终是基本数据类型的值作比较
        System.out.println("i1New72=i2+i3 " + (i1New72 == i1 + i3)); //true
        System.out.println("i4New72=i5+i6 " + (i4New72 == i5 + i6)); //true
 
        //因为 i2+i3 做算数运算+时,会自动拆箱再做加法,即拆箱后的基本数据类型char做加法运算,计算结果是整型的72;
        // i4New72与基本数据类型72比较的时候也会自动拆箱,所以最终是基本数据类型的值作比较
        System.out.println("i4=i5+i6 " + (i4New72 == i5 + i6) +" 因为:i5+i6= " + (i5 + i6)); //true
 
        Character c = '(';
        System.out.println("字符‘(’的码点值:" + (int)c); //40
 
        /* Caracter类中有缓存静态内部类CharacterCache;缓存范围:0~127,共128(cache.length)个值
        private static class CharacterCache {
            private CharacterCache(){}
 
            static final Character cache[] = new Character[127 + 1];
 
            static {
                for (int i = 0; i < cache.length; i++)
                    cache[i] = new Character((char)i);
            }
        }
         */
    }

(4)Integer

    static void testInt(){
        System.out.println("Boolean类型:");
        Integer i1 = 127;
        Integer i2 = 127;
        Integer i3 = 0;
        Integer i4 = new Integer(127);
        Integer i5 = new Integer(127);
        Integer i6 = new Integer(0);
        Integer i1New = 128;
        Integer i2New = 128;
 
        System.out.println("i1=i2 " + (i1 == i2));  //true 因为数值在[-128,127]的范围内,使用常量池缓存中的127
 
        System.out.println("i1New=i2New " + (i1New == i2New));  //false 超过缓存范围,创建新对象了
 
        System.out.println("i1=i4 " + (i1 == i4)); //false 因为i1指向常量池对象127,i4指向堆中对象127
 
        System.out.println("i4=i5 " + (i4 == i5)); //false 因为i4和i5是堆中两个对象
 
        //因为 i5+i6 做算数运算+时,会自动拆箱再做加法,所以结果是拆箱后的基本数据类型int,所以最终是基本数据类型的值作比较
        System.out.println("127=i5+i6 " + (127 == i5 + i6)); //true
 
        //因为 i2+i3 做算数运算+时,会自动拆箱再做加法,所以结果是拆箱后的基本数据类型int;i1与基本数据类型比较的时候也会自动拆箱
        System.out.println("i1=i2+i3 " + (i1 == i2 + i3)); //true
 
        //因为 i5+i6 做算数运算+时,会自动拆箱再做加法,所以结果是拆箱后的基本数据类型int;
        //i4与i5+i6的基本数据类型int结果比较时,i4也会自动拆箱,所以最终是基本数据类型的值作比较
        System.out.println("i4=i5+i6 " + (i4 == i5 + i6)); //true
 
        /* Integer类中有缓存静态内部类IntegerCache;默认缓存范围:-128~127,共256(cache.length)个值;
            但是可通过 java.lang.Integer.IntegerCache.high 修改高位值,例如:设置vm参数 -XX:AutoBoxCacheMax=200 即
            可修改缓存上限为200
        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() {}
        }
         */
    }

Idea2021通过配置VM options修改Integer缓存上限,具体配置参考:

Idea2021.3.2 设置项目运行参数配置_hnjcxy的博客-CSDN博客Idea2021.3.2 设置运行参数配置:Program arguments 、 Environment variables 和 VM options。1、点击Run -> Edit Configurations2、在打开的窗口可以设置 Program arguments 和 Environment variables 参数,如果需要设置VM参数,请看第三步设置VM参数。设置Program arguments参数时,多个参数中间用空格分开,如:"22" "33" "44"。.imghttps://blog.csdn.net/hnjcxy/article/details/123791208

(5)Long

    static void testLong(){
        System.out.println("Long类型:");
        Long i1 = 127L;
        Long i2 = 127L;
        Long i3 = 0L;
        Long i4 = new Long(127L);
        Long i5 = new Long(127L);
        Long i6 = new Long(0);
        Long i1New = 128L;
        Long i2New = 128L;
 
        System.out.println("i1=i2 " + (i1 == i2));  //true 因为数值在[-128,127]的范围内,使用常量池缓存中的127L
 
        System.out.println("i1New=i2New " + (i1New == i2New));  //false 超过缓存范围,创建新对象了
 
        System.out.println("i1=i4 " + (i1 == i4)); //false 因为i1指向常量池对象127L,i4指向堆中对象127L
 
        System.out.println("i4=i5 " + (i4 == i5)); //false 因为i4和i5是堆中两个对象
 
        //因为 i5+i6 做算数运算+时,会自动拆箱再做加法,所以结果是拆箱后的基本数据类型long,所以最终是基本数据类型的值作比较
        System.out.println("127L=i5+i6 " + (127L == i5 + i6)); //true
 
        //因为 i2+i3 做算数运算+时,会自动拆箱再做加法,所以结果是拆箱后的基本数据类型long;i1与基本数据类型比较的时候也会自动拆箱
        System.out.println("i1=i2+i3 " + (i1 == i2 + i3)); //true
 
        //因为 i5+i6 做算数运算+时,会自动拆箱再做加法,所以结果是拆箱后的基本数据类型long;
        //i4与i5+i6的基本数据类型long结果比较时,i4也会自动拆箱,所以最终是基本数据类型的值作比较
        System.out.println("i4=i5+i6 " + (i4 == i5 + i6)); //true
 
        /* long类中有缓存静态内部类ByteCache;缓存范围:-128~127,共256(cache.length)个值
        private static class LongCache {
            private LongCache(){}
            static final Long cache[] = new Long[-(-128) + 127 + 1];
            static {
                for(int i = 0; i < cache.length; i++)
                    cache[i] = new Long(i - 128);
            }
        }
         */
 
    }

(6)Boolean

    static void testBool(){
        System.out.println("Boolean类型:");
        Boolean i1 = true;
        Boolean i2 = true;
        Boolean i4 = new Boolean("true");
        Boolean i5 = new Boolean("true");
 
        System.out.println("i1=i2 " + (i1 == i2));  //true 因为i1、i2使用常量池缓存中的true
 
        System.out.println("i1=i4 " + (i1 == i4)); //false 因为i1指向常量池对象true,i4指向堆中对象true,所以两个对象地址不同
 
        System.out.println("i4=i5 " + (i4 == i5)); //false 因为i4和i5是堆中两个对象,比较的是两个对象地址
 
        //因为 i5 与常量true比较时,会自动拆箱为基本数据类型boolean,所以最终比较的是值,不是对象地址
        System.out.println("true=i5+i6 " + (true == i5)); //true
 
    }

(7)Double 和 Float 没有缓存

    static void testDouble(){
        System.out.println("Double类型:");
        Double i1 = 127.0;
        Double i2 = 127.0;
        Double i3 = 0.0;
        Double i4 = new Double(127.0);
        Double i5 = new Double(127.0);
        Double i6 = new Double(0);
 
        System.out.println("i1=i2 " + (i1 == i2));  //false 没有缓存,是两个不同的Double类型对象
 
        //因为 i2+i3 做算术运算+时,会自动拆箱再做加法,所以结果是拆箱后的基本类型double数值127.0,i1与基本数据类型比较时,
        // 也需要拆箱成基本数据类型,最后比较两个基本数据类型127.0的值是否相等
        System.out.println("i1=i2+i3 " + (i1 == i2 + i3)); //true
 
        System.out.println("i1=i4 " + (i1 == i4)); //false 没有缓存,是两个不同的Double类型对象
 
        System.out.println("i4=i5 " + (i4 == i5)); //false 没有缓存,是两个不同的Double类型对象
 
        //因为 i5+i6 做算数运算+时,会自动拆箱再做加法,所以结果是基本数据类型double;最后比较两个基本数据类型127.0的值是否相等
        System.out.println("127.0=i5+i6 " + (127.0 == i5 + i6)); //true
        System.out.println("Double计算后,类型为:"+ myGetType(i5 + i6));  // int
 
        //因为 i5+i6 做算数运算+时,会自动拆箱再做加法,所以结果是基本数据类型double;i4与i5+i6的基本数据类型结果比较时,
        // i4也会自动拆箱成基本数据类型double,最后是比较基本数据类型的值,而不是比较封装类对象地址
        System.out.println("i4=i5+i6 " + (i4 == i5 + i6)); //true
 
 
    }
测试中用到的判断基本数据类型的方法:
//判断类型
    public static String myGetType(Object o) {
        String type = o.getClass().getSimpleName();
        if ("Integer".equals(type)) {
            return String.valueOf(Integer.TYPE);
        } else if ("Long".equals(type)) {
            return String.valueOf(Long.TYPE);
        } else if ("Float".equals(type)) {
            return String.valueOf(Float.TYPE);
        } else if ("Double".equals(type)) {
            return String.valueOf(Double.TYPE);
        } else if ("Short".equals(type)) {
            return String.valueOf(Short.TYPE);
        } else if ("Byte".equals(type)) {
            return String.valueOf(Byte.TYPE);
        } else if ("Character".equals(type)) {
            return String.valueOf(Character.TYPE);
        } else if ("Boolean".equals(type)) {
            return String.valueOf(Boolean.TYPE);
        }
        return "非基本数据类型!";
    }
posted @ 2023-06-23 13:33  哩个啷个波  阅读(164)  评论(0编辑  收藏  举报