包装类的概念
java有着万物皆对象的理念,而基本数据类型并不具有对象的性质,包装类的出现,相当于把基本类型"包装"起来,使其具有对象的性质,如一些属性和方法。
而当我们想HashMap等一些容器里放东西时,基本数据类型时放不进去的,需要放入对象,这是就需要对应的基本数据类型的包装类了。
基本数据类型对应的包装类
基本数据类型: boolean,char,byte,short,int,long,float,double
包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double
基本数据类型和包装类之间的转换
基本类型 -> 包装类 (装箱)
1.以int转Integer为例 (下面都以int为例)
int num = 456;
Integer int1 = new Integer(num); //手动装箱
Integer int2 = num; //自动装箱 (JDK 5 的新特性)
这里需要注意的是,当你-128 <= num <= 127 时,两个对象的引用地址是相同。(注,这是自动装箱的情况下,手动装箱每次都生成新的对象)
int num1 = 127;
Integer int3 = num1;
Integer int4 = num1;
System.out.println(int3 == int4);
#true
int num1 = 129;
Integer int3 = num1;
Integer int4 = num1;
System.out.println(int3 == int4);
#false
这是因为自动装箱,相当于调用了Integer.valueOf()方法
源码:
public static Integer valueOf(int i) {
return i >= -128 && i <= Integer.IntegerCache.high ? Integer.IntegerCache.cache[i + 128] : new Integer(i);
} //默认Integer.IntegerCache.high = 127
先判断i值是否在-128和127之间,如果在-128和127之间则直接从IntegerCache.cache缓存中获取对应的包装类;不存在则new出一个新的对象。
再看IntegerCache内部
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer[] cache;
static Integer[] archivedCache;
private IntegerCache() {
}
static {
int h = 127;
String integerCacheHighPropValue = VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
int size;
if (integerCacheHighPropValue != null) {
try {
size = Integer.parseInt(integerCacheHighPropValue);
size = Math.max(size, 127);
h = Math.min(size, 2147483518);
} catch (NumberFormatException var6) {
}
}
high = h;
VM.initializeFromArchive(Integer.IntegerCache.class);
size = high - -128 + 1;
if (archivedCache == null || size > archivedCache.length) {
Integer[] c = new Integer[size];
int j = -128;
for(int k = 0; k < c.length; ++k) {
c[k] = new Integer(j++);
}
archivedCache = c;
}
cache = archivedCache;
assert high >= 127;
}
}
可以看到内部有一个静态数组cache,在类加载的时候,执行static静态块进行-128到127数字之间的Integer对象,存放到cache数组中。
注:八种基本类型中double和float的自动装箱并没有缓存,因为是浮点型。
包装类 -> 基本类型 (拆箱)
int int5 = int3; // 自动拆箱
int int6 = int3.intValue(); // 手动拆箱
public int intValue() {
return this.value;
}
自动拆箱也就是使用了intValue() 方法
基本数据类型和String类型之间的转换
基本类型 -> String
1.+" "
String str = num + "";
2.String.valueOf(num)
String str = String.valueOf(num);
3.Integer.toString(num)
String str = Integer.toString(num);
public static String valueOf(Object obj) {
return obj == null ? "null" : obj.toString();
}
public static String valueOf(int i) {
return Integer.toString(i);
}
public static String toString(int i) {
int size = stringSize(i);
byte[] buf;
if (String.COMPACT_STRINGS) {
buf = new byte[size];
getChars(i, size, buf);
return new String(buf, (byte)0);
} else {
buf = new byte[size * 2];
StringUTF16.getChars(i, size, buf);
return new String(buf, (byte)1);
}
}
这里可以看到当传入的obj为null时,返回的时字符串null,并且使用valueof时不用考虑是否为空,而使用toString时如果传入对象为null,则会导致java.lang.NullPointerException(传入参数为对象时的情况,基本数据类型没有null因此可以不用考虑,再下面包装类转String时需要考虑)
String - > 基本数据类型
1.Integer.parseInt(str)
String s = "5631351";
int n = Integer.parseInt(s);
public static int parseInt(String s) throws NumberFormatException {
return parseInt(s, 10);
}
2.Integer.valueOf(str)
int n = Integer.valueOf(s);
public static Integer valueOf(String s) throws NumberFormatException {
return parseInt(s, 10);
}
我们可以看到两种方法最后都是调用了 parseInt(s, 10) 方法
但是两者有一些区别,Integer.parseInt(str) 返回的是int基本类型
Integer.valueOf(str) 返回的是Integer对象类型,由于 parseInt(s, 10) 方法返回的是int类型,因此自动装箱成Integer类型(因此也需要判断是否在缓存范围内,如果在范围内,那么解析出来的Integer对象是同一个,根据Integer.valueOf()),之后Integer自动拆箱,得到int类型 。
包装类和String类型之间的转换
包装类 - > String
1.Integer.toString()
String sr = "1";
Integer i1 = Integer.valueOf(sr);
String strd = i1.toString();
String - > 包装类
1.Integer.valueOf(str)
Integer i1 = Integer.valueOf(sr);