8大基本类型的包装类型缓存

 

分类专栏: Java

自身范围缓存

boolean

boolean 的包装类型,缓存最简单,直接定义为静态常量就可以

public final class Boolean implements java.io.Serializable,
                                      Comparable<Boolean>
{
    public static final Boolean TRUE = new Boolean(true);

    public static final Boolean FALSE = new Boolean(false);

    public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
    }
}

char

ascii 码范围为 0-127, 这里只缓存ascii码范围的char 
Character 静态内部类 CharacterCache

不过通过下面这段代码可以看出来,他的范围是: 0<=x<=127

public final
class Character implements java.io.Serializable, Comparable<Character> {

    public static Character valueOf(char c) {
        if (c <= 127) { // must cache
            return CharacterCache.cache[(int)c];
        }
        return new Character(c);
    }

    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);
        }
    }
}

byte

byte 的范围是: -128<=x<=127

所以byte 一定是从缓存里面获取

-(-128) + 127 + 1 这一段的意思就是说 (-128~-1)+(1~127)+0 一共256个数

public final class Byte extends Number implements Comparable<Byte> {
  public static Byte valueOf(byte b) {
        final int offset = 128;
        return ByteCache.cache[(int)b + offset];
  }

  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));
      }
  }
}

范围为256的缓存

short

和byte 范围一样, 但是如果超过了 -128<=x<=127 这个范围,就不会从缓存中获取了

public final class Short extends Number implements Comparable<Short> {
    public static Short valueOf(short s) {
        final int offset = 128;
        int sAsInt = s;
        if (sAsInt >= -128 && sAsInt <= 127) { // must cache
            return ShortCache.cache[sAsInt + offset];
        }
        return new Short(s);
    }

    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));
        }
    }
}

int (可以通过参数配置上限)

这里的从缓存中获取的代码是一样的,重点是 IntegerCache 的范围是可以配置的

从源码中可以看出来 最低值一定是-128 是不可以修改的,但是上限值high 是可以修改的。

通过jvm参数: -Djava.lang.Integer.IntegerCache.high=1024 修改为1024

  1. 判断是否有jvm参数java.lang.Integer.IntegerCache.high
  2. 解析为 int 类型(解析失败就用默认值127)
  3. 修改最大值和最小值  

     4.  将 low<=x<=high的值加入到缓存

     5.  验证 IntegerCache.high > 127

 

  • 如果小于127 那么 high = 127

  • 如果小于127 那么 high = 127

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

     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 无法断点,因为在进入main方法之前,就已经被其他的类加载了.

long

范围: -128<=x<=127

public final class Long extends Number implements Comparable<Long> {
    public static Long valueOf(long l) {
        final int offset = 128;
        if (l >= -128 && l <= 127) { // will cache
            return LongCache.cache[(int)l + offset];
        }
        return new Long(l);
    }

    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);
            }
     }
}

不被缓存

valueOf 时, 直接new 包装类型的对象,然后返回

float

public final class Float extends Number implements Comparable<Float> {
  public static Float valueOf(float f) {
        return new Float(f); 
  }
}

double

public final class Double extends Number implements Comparable<Double> {
    public static Double valueOf(double d) {
        return new Double(d);
    }
}

<think>好的,我现在需要回答用户关于Java基本数据类型包装的问题。首先,我得确认自己对这一块的知识掌握情况,避免出现错误。 首先,Java有八种基本数据类型,每种都有对应的包装。我记得分别是byte对应Byte,short对应Short,int对应Integer,long对应Long,float对应Float,double对应Double,char对应Character,boolean对应Boolean。对吗?对的,没错。 接下来,用户可能想知道为什么需要这些包装。主要是Java的泛型、集合如ArrayList只能存储对象,不能存基本类型,这时候必须用包装。另外,包装提供了很多有用的方法,比如类型转换、数值处理等。比如Integer.parseInt()这个方法,可以把字符串转成int,这个应该属于包装的实用方法。 然后,自动装箱和拆箱的概念很重要。Java 5之后引入了自动装箱和拆箱,这样可以直接在基本类型包装之间自动转换,比如Integer i = 10; 实际是Integer i = Integer.valueOf(10); 拆箱则是反过来,比如int j = i; 实际上是int j = i.intValue();。但要注意自动装箱的缓存机制,比如Integer对于-128到127的值会缓存,超出范围会新建对象。这部分需要解释清楚,避免用户在使用时出现对象比较的问题,比如用==比较两个超出缓存范围的Integer对象会得到false,这时候应该用equals方法。 然后需要讲每个包装的继承结构。比如,Number是Byte、Short、Integer、Long、Float、Double的父,而Character和Boolean直接继承自Object。这可能会影响类型转换和方法的使用,比如通过Number的方法获取数值的不同形式。 还要提到包装的常用方法,比如valueOf()、parseXxx()、toString()、xxxValue()等方法。比如Double.valueOf("3.14")转换成Double对象,Integer.parseInt("123")得到int值。这些方法对于类型转换和字符串处理非常有用。 另外,需要注意包装的不可变性。一旦创建,包装对象的值就不能改变,比如Integer对象的值是final的。每次修改都会生成新的对象,这可能影响性能和内存使用,尤其是在量操作时需要注意。 可能还需要比较基本类型包装的区别,比如基本类型存储在栈上,效率更高,而包装是对象,存在堆里,有对象头的开销。所以在性能敏感的地方还是应该使用基本类型,但在需要使用对象特性的场合必须用包装。 用户可能还会遇到空指针的问题,因为包装可以为null,而基本类型不能。比如拆箱的时候如果包装对象是null,会抛出NullPointerException,这也是需要注意的地方。 最后,可以举一些例子,比如集合的使用,或者方法参数需要对象时的处理。比如List<Integer> list = new ArrayList<>(); 这里必须用Integer。或者在使用反射时,可能需要处理包装的情况。 总结一下,回答的结构应该是先介绍基本数据类型对应的包装,然后讲为什么需要它们,自动装箱拆箱,常用方法,注意事项,继承结构,不可变性,性能考虑,以及常见问题如空指针和对象比较。这样用户就能全面了解包装的用途和使用方法了。</think>Java基本数据类型包装是为解决基本数据类型无法直接参与面向对象操作而设计的。以下是逐步说明: --- ### 一、8基本类型包装对应关系 1. **byte** → **`Byte`** 2. **short** → **`Short`** 3. **int** → **`Integer`** 4. **long** → **`Long`** 5. **float** → **`Float`** 6. **double** → **`Double`** 7. **char** → **`Character`** 8. **boolean** → **`Boolean`** --- ### 二、包装的作用 1. **对象化操作** 允许基本类型以对象形式存在,便于存入集合(如`ArrayList<Integer>`)。 2. **提供工具方法** 例如类型转换、进制转换、最值/最小值常量等。 ```java int num = Integer.parseInt("123"); // 字符串转int String binary = Integer.toBinaryString(10); // 十进制转二进制 ``` 3. **支持泛型** 泛型参数需为对象类型(如`List<Integer>`)。 --- ### 三、自动装箱(Autoboxing)与拆箱(Unboxing) Java 5+ 支持自动转换: - **装箱**:基本类型包装 $$ \text{Integer} \ i = 10 \quad \text{等价于} \quad \text{Integer} \ i = \text{Integer.valueOf(10)} $$ - **拆箱**:包装基本类型 $$ \text{int} \ j = i \quad \text{等价于} \quad \text{int} \ j = i.\text{intValue()} $$ --- ### 四、注意事项 1. **对象比较问题** 用`==`比较包装对象时,可能因缓存范围(如`Integer`缓存-128~127)导致错误结果。 ✅ 正确做法:使用`equals()`比较值。 ```java Integer a = 200; Integer b = 200; System.out.println(a == b); // false(超出缓存范围) System.out.println(a.equals(b)); // true ``` 2. **空指针风险** 拆箱时若对象为`null`,会抛出`NullPointerException`。 ```java Integer i = null; int j = i; // 抛出NullPointerException ``` 3. **性能差异** 包装存储在堆内存,频繁操作可能影响性能。优先在集合、泛型等场景使用。 --- ### 五、常用方法 | 方法 | 说明 | |------|------| | `valueOf()` | 将基本类型/字符串转为包装对象 | | `parseXxx()` | 将字符串转为基本类型(如`Integer.parseInt()`) | | `xxxValue()` | 拆箱为基本类型(如`i.intValue()`) | | `compareTo()` | 比较两个包装对象的值 | | `toString()` | 转为字符串 | --- ### 六、继承关系 - **数值型包装**(如`Integer`、`Double`)继承自`Number`,提供`intValue()`、`doubleValue()`等方法。 - **非数值型**(`Character`、`Boolean`)直接继承`Object`。 --- ### 总结 包装通过对象化扩展了基本类型的功能,但需注意比较、空指针和性能问题。合理利用自动装箱/拆箱能简化代码,但在高频操作时建议优先使用基本类型
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值