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自我学习路线
一、包装类概述
- 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类中的方法就用不着了,以下只做简单说明
- byte byteValue()
以 byte 形式返回指定的数值 - abstract double doubleValue()
以 double 形式返回指定的数值 - abstract float floatValue()
以 float 形式返回指定的数值 - abstract int intValue()
以 int 形式返回指定的数值 - abstract long longValue()
以 long 形式返回指定的数值 - 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