当前位置: 移动技术网 > IT编程>开发语言>Java > JavaSE 包装类与装箱拆箱

JavaSE 包装类与装箱拆箱

2020年07月27日  | 移动技术网IT编程  | 我要评论

一、包装类概述

  • Java中为8种基本数据类型对应准备了8种包装类型,8种包装类属于引用数据类型,父类是Object
  • 8种基本数据类型对应的包装类型名:

1. Number

  • Number是一个抽象类,无法实例化对象
package java.lang;

public abstract class Number implements java.io.Serializable {
    public abstract int intValue();

    public abstract long longValue();

    public abstract float floatValue();

    public abstract double doubleValue();

    public byte byteValue() {
        return (byte)intValue();
    }

    public short shortValue() {
        return (short)intValue();
    }

    private static final long serialVersionUID = -8742448824652078965L;
}

2. Number方法

  • 以下方法所有的数字包装类的子类都有,但JDK1.5之后支持了自动装箱与拆箱,所以Number类中的方法就用不着了,以下只做简单说明
  1. byte byteValue()
    以 byte 形式返回指定的数值
  2. abstract double doubleValue()
    以 double 形式返回指定的数值
  3. abstract float floatValue()
    以 float 形式返回指定的数值
  4. abstract int intValue()
    以 int 形式返回指定的数值
  5. abstract long longValue()
    以 long 形式返回指定的数值
  6. short shortValue()
    以 short 形式返回指定的数值

二、 装箱与拆箱

1. 装箱与拆箱概述

  • 装箱:将基本数据类型转换为包装器类型(引用数据类型)
  • 拆箱:将包装器类型(引用数据类型)转换为基本数据类型
  • JDK1.5之后支持自动装箱与拆箱
public class Test {
	public static void main(String[] args) {
		// 手动装箱(过时)
		Integer x = new Integer(3);
		// 手动拆箱(过时)
		int y = x.intValue();
		System.out.println(y); // 3
		
		// 自动装箱
		Integer a = 4;
		// 自动拆箱
		int b = a;
		System.out.println(b); // 4
	}
}
  • NumberFormatException数字格式异常
public class Test {
	public static void main(String[] args) {
		/**
		 * 	编译正常
		 * 	运行异常:java.lang.NumberFormatException
		 */
		Integer i = new Integer("创建日期");
		System.out.println(i);
	}
}
  • 静态方法
    static int parseInt(String s)
public class Test04 {
	public static void main(String[] args) {
		/**
		 * static int parseInt(String s)
		 * 静态方法,传参String,返回int
		 */
		String str = "123";
		int i = Integer.parseInt(str);
		System.out.println(i); // 输出int类型的123
	}
}

2. 源码解析

  • Java装箱过程是调用包装类的valueOf方法实现的,而拆箱过程则是调用包装类的xxxValue方法实现的(xxx代表对应的基本数据类型)
  • 以Integer为例,判断以下代码的结果:
public class Test {
	public static void main(String[] args) {
		/**
		 * 	自动装箱的结果比较(由valueOf方法实现)
		 * 	Integer采用了缓存机制
		 * 	Double没有采用缓存机制
		 */
		Integer i1 = -128;
		Integer i2 = -128;
		Integer i3 = 100;
		Integer i4 = 100;
		Integer i5 = 127;
		Integer i6 = 127;
		
		Double d1 = 10.0;
		Double d2 = 10.0;
		Double d3 = 200.0;
		Double d4 = 200.0;

		System.out.println(i1 == i2); // true
		System.out.println(i3 == i4); // true
		System.out.println(i5 == i6); // false
		
		System.out.println(d1 == d2); // false
		System.out.println(d3 == d4); // false
	}
}
  • Integer valueOf()源码:
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)]; // 符合取值范围时,进入已创建好的静态IntergerCache中(预加载的缓存),i + (-IntegerCache.low)的值表示去取cache数组中那个下标的值
    return new Integer(i); // 当不符合取值范围时,创建新的对象,即new开辟新的内存空间,此时不属于IntergerCache管理区
}
  • Integer类的内部类IntegerCache源码:
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() {}
    }
  • 符合取值范围时,进入已创建好的静态IntergerCache中(预加载的缓存),i + (-IntegerCache.low)的值表示去取cache数组中那个下标的值
  • 当不符合取值范围时,创建新的对象,即new开辟新的内存空间,此时不属于IntergerCache管理区
  • 使用此方式的好处
    尽管预加载缓存占用了部分内存,但为了更好地节约内存开销,在[-128,127]范围的Integer包装类型直接从预加载的缓存中去取,不在[-128,127]范围的则需要重新创建对象,即new开辟新的内存空间,如果没有缓存机制,那么只要是装箱,则需要全部声明新的Integer对象,即开辟更多的内存空间,会导致内存不断浪费
  • intValue()源码(联想byte、short、long、char):
public int intValue() {
    return value; // 直接返回拆箱后的结果
}
  • Boolean valueOf()源码:
public static Boolean valueOf(boolean b) {
	/**
	 *	TRUE与FALSE是一个对象
	 *	声明方式:
	 *	public static final Boolean TRUE = new Boolean(true);
	 *	public static final Boolean FALSE = new Boolean(false);
	 *	因为只有两种情况,所以在内部已经提前创建好两个对象,为了避免重复创建对象
	 */
    return (b ? TRUE : FALSE);
}
  • Double valueOf()源码(Float同理):
public static Double valueOf(double d) {
	/**
	 * 	在某个范围内,浮点数的个数是无限的,所以Double没有采用缓存机制
	 * 	Double直接创建一个对象,所以每次创建的对象都不一样
	 */
    return new Double(d);
}
  • 取值范围总结
    Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的
    Double、Float的valueOf方法的实现是类似的,每次都返回不同的对象
    Boolean单独

3. 装箱与拆箱时机

public class Test {
	public static void main(String[] args) {
		/**
		 * 两个Integer对象相加时,编译器会将Integer拆箱为int相加
		 * 即所得和为int类型,此时也无法比较,所以将前者同理拆箱为int类型
		 */
		Integer i1 = new Integer(100);
		Integer i2 = new Integer(100);
		Integer i3 = new Integer(0);
		
		System.out.println(i1 == i2); // false
		System.out.println(i1 == i2 + i3); // true
	}
}

附、String、int、Integer相互转换

public class Test {
	public static void main(String[] args) {
		// String --> int
        int i1 = Integer.parseInt("100"); // i1是数字100
        System.out.println(i1 + 1); // 101

        // int --> String
        String s2 = i1 + "";
        System.out.println(s2); // "100"

        // int --> Integer
        // 自动装箱
        Integer x = 1000;

        // Integer --> int
        // 自动拆箱
        int y = x;

        // String --> Integer
        Integer k = Integer.valueOf("123");

        // Integer --> String
        String e = String.valueOf(k);
	}
}

本文地址:https://blog.csdn.net/LvJzzZ/article/details/107579583

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网