JAVANumber类和自动装箱,拆箱

  • Post author:
  • Post category:java




Number类

所有的包装类(Integer、Long、Byte、Double、Float、Short)都是抽象类 Number 的子类。提供了将包装类型拆箱成基本类型的方法,所有基本类型的包装类型都继承了该抽象类,并且是final声明不可继承改变xxxValue() //方法用于将 Number 对象转换为 xxx 数据类型的值并返回,也叫拆箱。

byteValue(); doubleValue(); floatValue(); intValue(); longValue(); shortValue();

valueOf() //方法用于返回给定参数的原生 Number 对象值,参数可以是原生数据类型, String等。该方法是静态方法。该方法可以接收两个参数一个是字符串,一个是基数

Integer valueOf(int i):返回一个表示指定的 int 值的 Integer 实例。

Integer valueOf(String s):返回保存指定的 String 的值的 Integer 对象。

Integer valueOf(String s, int radix): 返回一个 Integer 对象,该对象中保存了用第二个参数提供的基数进行解析时从指定的 String 中提取的值。

compareTo() //方法用于将 Number 对象与方法的参数进行比较。可用于比较 Byte, Long, Integer等,该方法用于两个相同数据类型的比较,两个不同类型的数据不能用此方法来比较。

public int compareTo( NumberSubClass referenceName ) //referenceName – 可以是一个 Byte, Double, Integer, Float, Long 或 Short 类型的参数。

.如果指定的数与参数相等返回0

.如果指定的数小于参数返回 -1

.如果指定的数大于参数返回 1

自动装箱和拆箱:

当一个基础数据类型与封装类进行==、+、-、*、/运算时,会将封装类进行拆箱,对基础数据类型进行运算。

装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。装箱的过程会创建对应的对象,这个会消耗内存,所以装箱的过程会增加内存的消耗,影响性能。

需要装箱拆箱的类型有:

Object --- Boolean(boolean)
       --- Character(char) 
       --- Number -------- Byte(byte)
                  -------- Short(short)
                  -------- Integer(int)
                  -------- Long(long)
                  -------- Float(float)
                  -------- Double(double)

一.现在就以Integer为例,来分析一下它的源码:

Integer total = 99;

执行上面那句代码的时候,系统为我们执行了: Integer total = Integer.valueOf(99);

int totalprim = total;

执行上面那句代码的时候,系统为我们执行了: int totalprim = total.intValue();

1.Integer.valueOf函数:(装箱)

public static Integer valueOf(int i) {


return i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];

} //如果i小于-128或者大于等于128,就创建一个Integer对象,否则执行SMALL_VALUES[i + 128]

(1)Integer的构造函数:

private final int value;

public Integer(int value) {


this.value = value;

}

public Integer(String string) throws NumberFormatException {


this(parseInt(string));

}

//它里面定义了一个value变量,创建一个Integer对象,就会给这个变量初始化。第二个传入的是一个String变量,它会先把它转换成一个int值,然后进行初始化。

(2)SMALL_VALUES[i + 128]:

private static final Integer[] SMALL_VALUES = new Integer[256]; //它是一个静态的Integer数组对象,也就是说最终valueOf返回的都是一个Integer对象

Integer i1 = 100; Integer i2 = 100;

//它们的值在[-128,128)这个范围内,它们会拿到SMALL_VALUES数组里面的同一个对象SMALL_VALUES[228],它们引用到了同一个Integer对象

2.intValue函数:(拆箱)

@Override

public int intValue() {


return value; //直接返回value值即可

}

通过Integer源码可以得出,Integer.valueOf() 方法会在数值[-128,127]之间会执行SMALL_VALUES[i + 128]对Integer进行缓存,不会再重新new一个,当数值大于127或者小于-128的时候则会执行Integer的构造函数重新new一个

1、都是封装类,都是new出来的,肯定不相等。因为对象的内存地址不一样。

2、都是封装类,都不是new出来的,如果值在-128~127之间,那就相等,否则不相等。

3、如果是封装类和基本类型进行比较,只要数值相等那就相等,否则就不相等。因为封装类和基本数据类型进行比较的时候会有一个自动拆箱操作。

4、都是基本数据类型,如果数值相等,那就相等;否则不相等。

Integer派别:Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的;

Double派别: Double、Float的valueOf方法的实现是类似的。每次都返回不同的对象。

二.以Double类型来说,我们就不能这样做,因为它在这个范围内个数是无限的,总结一句就是:在某个范围内的整型数值的个数是有限的,而浮点数却不是。

在Double里面的做法很直接,就是直接创建一个对象,所以每次创建的对象都不一样,贴上源码:

public static Double valueOf(double d) {


return new Double(d);

}

三.Boolean类型

public static Boolean valueOf(boolean b) {


return b ? Boolean.TRUE : Boolean.FALSE; //执行valueOf返回的都是相同的对象

}

可以看到它并没有创建对象,因为在内部已经提前创建好两个对象,因为它只有两种情况,这样也是为了避免重复创建太多的对象。

在相比较过程中可能遇到equals()方法。

看看equals源码:(以Integer为例)

@Override

public boolean equals(Object o) {


return (o instanceof Integer) && (((Integer) o).value == value);

}

它必须满足两个条件才为true:

1、类型相同

2、内容相同

包装器类型调用equals(基本类型)方法,先会进行自动装箱,基本类型转换为包装器类型。

“==”运算符的两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)

注意,如果在一个表达式中混合使用 Integer 和 Double 类型,Integer 值就会拆箱,提升为 double,再装箱为 Double:



版权声明:本文为yxl995原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。