为何要包装类
故此,针对Java基本数据类型封装了包装类,每一个基本类型都有一个对应的包装类,以下是详情:
八大基本数据类型的包装类都使用final修饰,都是最终类,都不能被继承。
// Byte
public final class Byte extends Number implements Comparable<Byte> {}
// Character
public final class Character implements java.io.Serializable,
Comparable<Character> {}
// Short
public final class Short extends Number implements Comparable<Short> {}
// Integer
public final class Integer extends Number implements Comparable<Integer> {}
// Long
public final class Long extends Number implements Comparable<Long> {}
// Float
public final class Float extends Number implements Comparable<Float> {}
// Double
public final class Double extends Number implements Comparable<Double> {}
// Boolean
public final class Boolean implements java.io.Serializable,
Comparable<Boolean> {}
方式一:
Integer i = Integer.value(13);
方式二:
Integer i = new Integer(13);
int value = i.intValue();
在Java 5之前的版本中,基本数据类型和包装类之间的转换是需要手动进行的,但Sun公司从Java5开始提供了的自动装箱(Autoboxing)和自动拆箱(AutoUnboxing)操作 ;
Integer i = 13;
Integer i = new Integer(13);
Int j = i;
自动装箱和自动拆箱,也是一个语法糖/编译器级别新特性,在底层依然是手动装箱、拆箱操作;但是在装箱操作中使用的是Integer.valueOf()方法,而不是直接new Integer();其他的几个包装类也是如此,装箱操作中使用的是各自的valueOf()方法。
switch支持的基本数据类型:byte,short,char,int;也支持对应的包装类。因为在底层,switch中会对包装类做手动拆箱操作。
考虑下面的代码:
Object obj = 17;
在上述代码语句中有如下的操作:
Object[] arr = {"A",12,3.14,true};// 这是完全可行的
/** Integer 构造器源码 **/
// 接收int类型数据构建Integer对象
public Integer(int value){
this.value = value;
}
// 接受字符串数据构建Integer对象
public Integer(String s) throws NumberFormatException {
this.value =parseInt(s,10);
}
其他的几个包装类型也是这样的规律,具体实现查看源码即可。
Integer i1 =new Integer(13); // 方式一,每次都会创建新对象,不推荐
Integer i2 = Integer.valueOf(13); // 方式二,推荐,底层使用了缓存。
int val = i1.intValue();
// 方式1:包装类.valueOf(String str):
Integer i = Integer.valueOf(“13”);
// 方式2:new 包装类(String str):
Integer i= new Integer(“13”);
String str = 对象.toString();
// 不止包装类对象,其他任何对象都可以使用toString()转换;
String str = 13 + "";
// parseXxx(String s) : xxx表示8大基本数据类型,如:
String input = ”12345”;
int value = Integer.parseInt(input);
Boolean b1 =newBoolean("true");// true
Boolean b1 =newBoolean("TRUE");// true
Boolean b1 =newBoolean("sjsj");// false
在包装类中提供了缓存设计,会对一定范围内的数据作缓存,如果数据在范围内,会优先从缓存中取数据,超出范围才会创建新对象;
包装类中的缓存设计,也称为享元模式。缓存设计会在包装类中的valueOf()方法中实现,所以才会推荐使用valueOf()方法来实现拆箱操作,如下是Integer类的valueOf()源码:
再查看缓存实现细节:
通过查看源码可知,JVM会对-128 到 127之间的做缓存,如果你的变量值在这个范围内,就会优先从缓存中取数据,否则就会创建新对象。当然这个缓存区间也是可以设置的。
那么以下这个例子就可以解释了:
public static void main(String[] args){
Integer i1 = Integer.valueOf(13);
Integer i2 = Integer.valueOf(13);
System.out.println(i1 == i2);
// 输出为true。因为13在[-128, 127]之间,但是并没有创建新对象
Integer i3 = Integer.valueOf(129);
Integer i4 = Integer.valueOf(129);
System.out.println(i3 == i4); // 输出为false, 因为129不在[-128, 127]之间,
// 是使用new Integer()创建了新对象,故比较为false
Integer i5 =129;
Integer i6 =129;
System.out.println(i5 == i6);// 输出为false
System.out.println(i5.equals(i6));
// 输出为true,建议:如果对象包装类对象的值作比较,
// 应选用包装类的equals方法。
}
我们再来看Integer的equals方法的实现源码:
可以发现,包装类在比较时会将包装类型拆箱为基本数据类型,并使用==做比较。
包装类型和基本数据类型的区别(以Integer与int的区别为例):
static String toBinaryString(int i); // 把十进制转换为二进制
static String toOctalString(int i); // 把十进制转换为八进制
static String toHexString(int i); // 把十进制转换为十六进制
其实,包装类就是把基本数据类对象化,包装类是基本数据类型的超集;在开发中,建议成员变量优先使用包装类型,局部变量优先考虑基本数据类型。
完结。老夫虽不正经,但老夫一身的才华