Loading

java包装类总结

Java 是号称面向对象的语言,所有的类型都是引用类型。
Object 类是所有类的父类,而且是唯一不用指定明确继承的类。
但是它里面有基本类型如 int 不是引用类型,也不是继承自 Object,所以 Java 需要一个这样的包装类来使其面向对象的完整性。
包装类同时也可以实现可空类型,即一个数值是空的。Java 集合中也只能放入包装类型,而不支持基本类型。
包装类的架构图
八大基本类型对应包装类

包装类与自动装箱拆箱

装箱就是 Java 将基本类型转换成对应的包装类型,比如将 int 转换成 Integer 对象。反之将 Integer 转换成 int 值,则称为拆箱。
装箱时,调用 valueOf 方法实现,比如 Integer.valueOf(100);
拆箱时,调用对应的 xxxValue 方法,比如 intValue() 方法。
java1.5 后有了自动装箱拆箱功能。
自动装箱拆箱时,由 Java 编译器自动实现转换。
赋值操作的时候,当两边类型不同,就会发生自动装箱拆箱。
自动装箱有性能损耗,在循环中应避免

Integer sum = 0;
for(int i=0; i<100; i++){
sum+=i;
}

上面的代码 sum+=i 可以看成 sum = sum + i,但是这个操作会把 sum 先拆箱,然后相加后再装箱。等价于下面的代码:

 Integer sum = new Integer(sum.intValue() + i;);

包装类缓存(重点)

Java 包装类的缓存机制,是在Java 5中引入的一个有助于节省内存、提高性能的功能。

Java 基本类型的包装类的大部分都提供了对象的缓存,实现方式是在类初始化时提前创建好会频繁使用的包装类对象,当需要使用某个包装类的对象时,如果该对象包装的值在缓存的范围内,就返回缓存的对象,否则就创建新的对象并返回。
只有在自动装箱时有效,使用构造函数创建对象不适用。
两种浮点数类型的包装类Float,Double并没有实现常量池技术。
在包装类中,缓存的基本数据类型值的范围如下:

基本数据类型 包装类型 缓存范围
byte Byte -128 ~ 127
short Short -128 ~ 127
int Byte -128 ~ 127
short Integer -128 ~ 127
long Long -128 ~ 127
char Character 0 ~ 127
float Float
double Double

代码示例

	Integer i1 = 12;  // 相当于 Integer.valueOf(12)
    Integer i2 = 12;

    Integer i3 = 200; //200>缓存上限127
    Integer i4 = 200;

    Integer i5 = new Integer(12);   // 会创建新的对象
    
	System.out.println(i1 == i2);   // true
    System.out.println(i3 == i4);   // false
    System.out.println(i1 == i5);   // false

由于i1,i2都在[-128, 127]范围内,所以从缓存中取,只要值相同,对象就相同,所以两者相等。

包装类缓存原理

1)当包装类加载时,该包装类中的内部类xxCache会初始化一个包装类类型数组,最小值(固定值)为-128,而最大值(默认值)为127【可修改】,这个长度的缓存值放在方法区的常量池中,是所有线程共享的。

 private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];//声明为final,所以缓存的对象会被放入常量池中;声明为statci,所以是在类加载的时候就创建好了
        //创建-128~127的值的包装类对象
        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() {}
    }

(2)当发生自动包装的时候,调用valueOf方法,对需要包装的基本类型的值进行判断,如果在缓存值的范围内,则返回缓存的对象,否则创建一个新的对象返回。
自动装箱的valueOf方法源码(Integer类型举例):

public static Integer valueOf(int i) {
    //其中low是最小值,high是最大值   在缓存范围内
   if (i >= IntegerCache.low && i <=IntegerCache.high)
   {
       //返回的是缓存中的对象
       return IntegerCache.cache[i + (-IntegerCache.low)];
   }

   return new Integer(i);
} 

包装类比较慎用==

从上面可以看出包装类==比较会受到受到缓存的影响。
推荐写法

  • 当两个数值都是包装类,最好用equals

  • 当其中一方是基本类型,用==

  • “>“或“< “随便怎么比,包装类之间比较也不出错

一条最根本的原则:

对于对象来说,本就不该用==来比较值。

posted @ 2022-03-05 21:22  程序员小小宇  阅读(110)  评论(0)    收藏  举报