欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaSE 包装类与装箱拆箱

程序员文章站 2022-04-15 19:21:25
Java自我学习路线一、包装类概述1. Number2. Number方法2.1 byte byteValue()2.2 abstract double doubleValue()2.3 abstract float floatValue()2.4 abstract int intValue()2.5 abstract long longValue()2.6 short shortValue()二、 装箱与拆箱1. 装箱与拆箱概述2. 源码解析3. 装箱与拆箱时机一、包装类概述Java中为8种...

一、包装类概述

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

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单独
    JavaSE 包装类与装箱拆箱

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