Java 基本数据类型包装类源码剖析

基本类型的包装类

Java的八种基本类型都有对应的包装类,包装类内部有一个实例变量,保存对应的基本类型的值,这个类一般还有一些静态方法、静态变量和实例方法,以方便对数据进行操作。

包装类的类名除了Integer和Character外,其他类名称与基本类型基本一样,只是首字母大写。

装包和拆包

包装类与基本类型的转换代码结构是类似的,每种包装类都有一个静态方法valueOf(),接受基本
类型,返回引用类型,也都有一个实例方法xxxValue()返回对应的基本类型。

以Integer和int转换为例:

int i = 123;
Integer ie = Integer.valueOf(i); // 装包,静态方法传入int
int j = ie.intValue(); // 拆包,Integer对象获取值

Java5 后可以自动装包和拆包

Integer a = 100;
int b = a;

编译时编译器将上面的代码替换为

Integer a = Integer.valueOf(100);
int b = a.intValue();

另外包装类也可以直接使用构造方法来创建

Integer a = new Integer(100);

一般建议使用valueOf方法。因为new每次都会创建一个新对象,而除了Float和Double外的其他包装类,都会缓存包装类对象,减少需要创建对象的次数,节省空间,提升性能。实际上,从Java9开始,这些构造方法已经被标记为过时了,推荐使用静态的valueOf方法。

重写Object方法

所有包装类都重写了Object类的如下方法:

boolean equals(Object obj)
int hashCode()
String toString()

其中equals和hashCode绑定

equals用于判断当前对象和参数传入的对象是否相同,Object类的默认实现是比较地址,对于两个变量,只有这两个变量指向同一个对象时,equals才返回true,它和比较运算符(==)的结果是一样的。
然而equals应该反映的是对象间的逻辑相等关系,所以这个默认实现一般是不合适的,子类需要重写该实现。所有包装类都重写了该实现,实际比较用的是其包装的基本类型值

public boolean equals(Object obj) {
    if(obj instanceof Integer) {
        return value == ((Integer)obj).IntegerValue();
    }
    return false;
}

Float有一个静态方法floatToIntBits(),将float的二进制表示看作int。需要注意的是,只有两个float的二进制表示完全一样的时候,equals才会返回true。

Double的equals方法与Float类似,它有一个静态方法doubleToLongBits,将double的二进制表示看作long,然后再按long比较。

hashCode返回一个对象的哈希值。哈希值是一个int类型的数,由对象中一般不变的属性映射得来,用于快速对对象进行区分、分组等。一个对象的哈希值不能改变,相同对象的哈希值必须一样。不同对象的哈希值一般应不同,但可以有对象不同但哈希值相同的情况。

包装类都重写了hashCode,根据包装的基本类型值计算hashCode,对于Byte、Short、Integer、Character,hashCode就是其内部值

public int hashCode() {
       return (int)value;
}

对于Boolean,因为只有true和false,选用两个质数作为哈希值,减少哈希冲突

public int hashCode() {
       return value ? 1231 : 1237;
}

对于Float,hashCode为int值

public int hashCode() {
       return floatToIntBits(value);
}

对于Long,hashCode为高32位与低32位进行位异或操作

无符号右移操作符(>>>)

public int hashCode() {
       return(int)(value ^ (value >>> 32));
}

实现Comparable接口

Comparable接口只有一个方法compareTo,当前对象与参数对象进行比较,在小于、等于、大于参数时,应分别返回-1、0、1。

对于Boolean,false小于true。

对于Float和Double,存在和equals方法一样的问题,0.01和0.1*0.1相比的结果并不为0。

public interface Comparable<T> {
       public int compareTo(T o);
}

和String互相转换

除了toString方法外,包装类还有一些其他与String相关的方法。除了Character外,每个包装类都有一个静态的valueOf(String)方法,根据字符串表示返回包装类对象

Boolean b = Boolean.valueOf("true");

还有一个静态的parseXXX(String)方法,根据字符串表示返回基本类型值

boolean b = Boolean. parseBoolean("true");

转化为String有一个静态的toString方法,根据基本类型值返回字符串表示

System.out. println(Boolean.toString(true));

输出true

常量

Boolean的TRUE和FALSE

public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);

所有数值类型都定义了最大值和最小值,对于Integer,在Java中,int类型占用32位,它能够表示的最小值为-2^31(0x80000000),最大值为2^31-1(0x7fffffff)。

public static final int MIN_VALUE = 0x80000000;
public static final int MAX_VALUE = 0x7fffffff;

Float和Double还定义了正无穷、负无穷、非数值,对于Double类

public static final double POSITIVE_INFINITY = 1.0 / 0.0; //正无穷
public static final double NEGATIVE_INFINITY = -1.0 / 0.0; //负无穷
public static final double NaN = 0.0d / 0.0; //非数值

抽象类Number

6种数值类型包装类有一个共同的父类Number。Number是一个抽象类,它定义了如下方法

byte byteValue()
short shortValue()
int intValue()
long longValue()
float floatValue()
double doublevalue()

因此包装类可以返回任意的数值类型

不可变限定

不可变不用操心数据被意外改写的可能,使得程序更为简单安全,可以安全地共享数据,尤其是在多线程的环境下。包装类都是不可变类,实例对象一旦创建,就没有办法修改了。

这是通过如下方式强制实现的:
·所有包装类都声明为了final,不能被继承。
·内部基本类型值是私有的,且声明为了final。
·没有定义setter方法。

  • 8
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值