JDK 源码之基础类 Integer
Contents
本片文章主要介绍 Integer 类中一些比较常用的方法,并分析该类在 Java 中的作用。
总览
在 java.lang
下的 Integer
类是我们平时经常使用的类,首先看一下该类的继承或实现关系,如下图所示:
可以看到,Integer
类继承了 Number
这一抽象类,又实现了 Comparable
接口。
抽象类 Number 是
BigDecimal
、BigInteger
、Byte
、Double
、Float
、Integer
、Long
以及Short
类的父类。而 Number 类的子类必须提供将所表示的数值转换为
byte
、double
、float
、int
、long
以及short
的方法。
Comparable
接口中只有一个 compareTo(T o)
方法,用于比较元素之间的大小。
属性
Integer 类中的重要属性(域)如下所示:
其中:
MIN_VALUE = 0x80000000
表示最小的常数值为 $ -2^{31} $,即 -2147483648;MAX_VALUE = 0x7fffffff
表示最大的常数值为 $ 2^{31}-1 $,即 2147483647;SIZE
用于表示 int 的二进制补码形式的值的比特位数;SIZES
用于表示 int 的二进制补码形式的字节数,值为SIZE / Byte.SIZE = 32 / 8
,即等于4
;public static final Class<Integer> TYPE
表示原始类型int
的 Class 实例。
此外,DigitTens
与 DigitOnes
如下所示:这俩用于获取从 0 到 99 之间某个数的 个位
和 十位
。例如 12,从 DigitOnes
中取出 2
,而从 DigitTens
中取出 1
。
|
|
digits
用于将数字表示为字符串的所有可能字符,如下所示:
|
|
sizeTable
属性与 stringSize(int x)
方法一起使用。它们用于计算一个 int 型的数字所对应字符串的长度,例如 12 所对应的字符串的长度就是 2,而 123 所对应的字符串的长度就是 3。
一般我们在计算一个数字有几位的时候,通常使用求余或除法进行计算,但这里使用了一个 sizeTable
数组来进行实现,也可以达到求位数的目的。
|
|
内部类 IntegerCache
IntegerCache
作为 Integer
的内部类,从命名方式就可以很清晰的看出,它主要和 缓存 有关。先看源码:
|
|
- 从第
4
行可以看到,该缓存是使用Integer
类型的cache[]
数组实现的,默认范围是[-128, 127]
。 - 从第
23
到第26
行可以看出,默认实例化了 256 个Integer
对象。
为什么需要缓存呢?
从文章开头你可以看到,int
的范围很大,将它们全部缓存起来的话代价很高。所以,当有一个新的 Integer
对象处于 [-128, 127] 中的时候,直接从缓存数组 cache[]
中取就好了,不用再重新实例化了,这样可以减小系统的开销。此外,在第 7
行的注释也说了,h
的值也可以通过设置虚拟机参数进行更改,即 Djava.lang.Integer.IntegerCache.high=xxx
。
常用方法
构造方法
两个构造方法如下所示:
|
|
至于 parseInt()
方法是什么,我们接着往下看。
parseInt() 方法
这里有两个 parseInt()
方法,这里主要看带有两个参数的方法即可,如下所示:
|
|
parseInt(String s, int radix)
方法与《剑指 Offer》中的题目「把字符串转换成整数」是类似的,都是将字符串转换成整数。
具体的解释已经在代码中标注了,但有一点需要注意的是:在转换过程中使用的是负数进行运算,因为 int 范围的最小值 Integer.MIN_VALUE
在变成正数的时候会导致溢出,所以这里用负数进行计算。
getChars() 方法
该方法主要是将某个 int 类型的数值放到 char 类型的 buf 数组里面,如下所示:
|
|
该方法将 int 类型的数值分为 高位的两个字节
和 低位的两个字节
分别进行处理。
int 占 4 个字节,1 字节 = 8 位,4 字节 = 32 位。
while (i >= 65536)
用于处理 int 高位的两个字节,也就是高 16 位。- 对于
for (;;)
内部,处理的是低 16 位,这里在计算 乘法 的时候使用的是 加法 和 移位 操作,计算起来更加高效。同时digits
数组用于获取对应的字符,这一点在之前已经提到过。
toString() 方法
这里有 3 个重载的 toString()
方法,如下所示:
|
|
对于第二个 toString()
方法,首先用 stringSize()
方法得到数值 i 的位数,然后利用 getChars()
方法获取数值 i 所对应的 char 数组,最后再 new 一个 String 返回。
对于第三个 toString()
方法,多了一个带有 进制 的参数。只要不在 2 到 36 进制之内的都会被处理成 十进制,这里首先将数值转换成 负数 进行处理,十进制转换成其它进制的方法就是不断的除以进制数,从而得到余数,然后将余数反过来,从而得到最后的结果。
valueOf() 方法
这里有三个 valueOf()
方法,如下所示:
|
|
重点看第一个 valueOf()
方法,这里有个 IntegerCache
缓存,对于缓存范围内的 Integer
对象,直接从缓冲中取就可以了,否则就需要重新 new
一个 Integer
对象,即实例化一个 Integer
对象。
这里涉及到了 自动装箱/自动拆箱,对于 -128 <= i <= 127
范围内的数值,返回的是缓存中的对象,并没有重新创建一个新对象,例如 Integer a = 123;
,这里就实现了 自动装箱
,将 int
类型的 123
转换成对应的包装类 Integer
,反编译源码可以看到,执行的就是调用了 ``valueOf()方法,即
Integer a = Integer.valueOf(123);`。
而对于范围以外的数,比如 128
来说,则会直接返回一个 Integer
对象。
而 自动拆箱
就是将 包装类型
转换成 基本数据类型
,如下所示:
|
|
这里的 int b = a;
通过反编译源码后可以看到,其实是调用了 intValue()
方法,即 int b = a.intValue();
。将 Integer
类型转换成 int
类型。
equals() 方法
equals()
方法首先判断对象 obj
是不是 Integer
类型,如果是的话,再将 obj
强转为 Integer
,通过 自动拆箱 再比较值是否相等。如下所示:
|
|
compare() 方法
这里直接 return 了一个三目运算,还是嵌套的三目运算。如果 x < y
,则返回 -1
;如果 x == y
,则返回 0
;如果 x > y
,则返回 1
。
|
|
除了以上的方法,其它的例如 reverse(int i)
、bitCount(int i)
、xxxValue()
等方法,在这里就不详细的展开了,你可以通过查看源码进行阅读。