JDK1.8源码-02-java.lang.Integer

JDK1.8源码-02-java.lang.Integer

上一篇介绍了 java.lang 包下的 Object 类,那么本篇接着介绍该包下的另一个类 Integer。

首先看看Integer类和int类型的区别:

  • Integer是int的包装类,int是八大数据类型之一(byte,char,short,int,long,float,double,boolean)
  • Integer是类,默认类型是null;int是基本数据类型,默认值是0;
  • Integer表示对象,用一个引用指向这个对象,而int是基本数据类型,直接存储数值。

1. 声明

1
public final class Integer extends Number implements Comparable<Integer>
  • Integer是用final声明的常量类,不能被任何类所继承

  • 并且Integer类继承了Number类和实现了Comparable接口。

    • Number类是一个抽象类,8种即基本数据类型的包装类除了Character 和 Boolean没有继承这个类以外,剩下的都继承了Number类,该类的各种方法用于数据类型的转换。
  • Comparable 接口就一个 compareTo 方法,用于元素之间的大小比较,下面会对这些方法详细展开介绍。

2. 主要属性

mark

mark

int类型在Java中占据四个字节,所以它的大小可以表示范围是 -2^31——2^31 -1

即-2147483648–>2147483647, 再用int类型的时候注意不要超出这个范围。

3. 构造方法

3.1 Integer(int)

对于第一个构造方法 Integer(int),源码如下,这没什么好说的。

1
2
3
4
5
6
7
8
9
10
/**
* Constructs a newly allocated {@code Integer} object that
* represents the specified {@code int} value.
*
* @param value the value to be represented by the
* {@code Integer} object.
*/
public Integer(int value) {
this.value = value;
}

3.2 Integer(String)

对于第二个构造方法Integer(String)就是将我们输入的字符串数据转换成整型数据。

首先我们必须要知道能转换成整数的字符串必须分成两个部分:

  • 第一位必须是“+”或者“-”

  • 之后的必须是0-9或者a-z字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//首先调用parseInt(s,10)方法,其中s表示我们需要转换的字符串,10表示以十进制输出,默认也是10进制    
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}

// 接下来看其中的parseInt方法
* <p>Examples:
* <blockquote><pre>
* parseInt("0", 10) returns 0
* parseInt("473", 10) returns 473
* parseInt("+42", 10) returns 42
* parseInt("-0", 10) returns 0
* parseInt("-FF", 16) returns -255
* parseInt("1100110", 2) returns 102
* parseInt("2147483647", 10) returns 2147483647
* parseInt("-2147483648", 10) returns -2147483648
* parseInt("2147483648", 10) throws a NumberFormatException
* parseInt("99", 8) throws a NumberFormatException
* parseInt("Kona", 10) throws a NumberFormatException
* parseInt("Kona", 27) returns 411787
* </pre></blockquote>
*
* @param s the {@code String} containing the integer
* representation to be parsed
* @param radix the radix to be used while parsing {@code s}.
* @return the integer represented by the string argument in the
* specified radix.
* @exception NumberFormatException if the {@code String}
* does not contain a parsable {@code int}.
*/

public static int parseInt(String s, int radix)
throws NumberFormatException
{
/*
* WARNING: This method may be invoked early during VM initialization
* before IntegerCache is initialized. Care must be taken to not use
* the valueOf method.
*/

// 如果转换成的字符串为null,直接抛出格式错误异常
if (s == null) {
throw new NumberFormatException("null");
}
// 如果转换的radix(默认是10)<2 则抛出数字格式异常,因为进制最小是 2 进制
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}

// 如果转换的radix(默认是10)> 36 则抛出数字格式异常,因为0到9一共10位,a到z一共26位,所以一共36位(即最高只能有36进制数)
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
}

int result = 0;
boolean negative = false;
int i = 0, len = s.length(); //len是待转换字符串的长度
int limit = -Integer.MAX_VALUE; //limit = -2147483647
int multmin;
int digit;

//如果待转换字符串长度大于 0
if (len > 0) {
// 获取待转换字符串的第一个字符
char firstChar = s.charAt(0);
// 这里主要用来判断第一个字符是“+”还是“-”号,因为这两个字符的ASCII都小于字符‘0’
if (firstChar < '0') { // Possible leading "+" or "-"
// 如果第一个字符是'-'
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+')
//如果第一个字符是不是 '+',直接抛出异常
throw NumberFormatException.forInputString(s);

// 待转换字符长度是1,不能使单独的“+”或者"-",否则抛出异常
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++; // 这里移动到第二位
}
multmin = limit / radix;
// 通过不断循环,将字符串除掉第一个字符之后,根据进制不断相乘再相加得到一个正整数。
// 举例:
// parseInt("2abc",16) = 2*16的3次方+10*16的2次方+11*16+12*1
// parseInt("123",10) = 1*10的2次方+2*10+3*1
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++),radix);
if (digit < 0) {
throw NumberFormatException.forInputString(s);
}
if (result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
result -= digit;
}
} else {
// 如果待转换字符串长度小于等于0,直接抛出异常
throw NumberFormatException.forInputString(s);
}
// 根据第一个字符得到的正负号,在结果前面加上符号
return negative ? result : -result;
}

4. toSring() 方法

这三个方法重载,能返回一个整型数据所表示的字符串形式

4.1 toString()

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* Returns a {@code String} object representing this
* {@code Integer}'s value. The value is converted to signed
* decimal representation and returned as a string, exactly as if
* the integer value were given as an argument to the {@link
* java.lang.Integer#toString(int)} method.
*
* @return a string representation of the value of this object in
* base&nbsp;10.
*/
public String toString() {
return toString(value);
}

4.2 toString(int i)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* Returns a {@code String} object representing the
* specified integer. The argument is converted to signed decimal
* representation and returned as a string, exactly as if the
* argument and radix 10 were given as arguments to the {@link
* #toString(int, int)} method.
*
* @param i an integer to be converted.
* @return a string representation of the argument in base&nbsp;10.
*/
public static String toString(int i) {
if (i == Integer.MIN_VALUE)
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
}

toString(int) 方法内部调用了 stringSize() 和 getChars() 方法,stringSize()它是用来计算参数i的位数也就是转换成字符串之后的字符串长度,内部结合一个已经初始化好的Int类型的数组sizeTable来完成这个计算。

1
2
3
4
5
6
7
8
9
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE };

// Requires positive x
static int stringSize(int x) {
for (int i=0; ; i++)
if (x <= sizeTable[i])
return i+1;
}

实现的方式很巧妙,注意负数包含符号位,所以对于负数的位数是stringSize(-i) + 1。

再来看看getChars方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
* Places characters representing the integer i into the
* character array buf. The characters are placed into
* the buffer backwards starting with the least significant
* digit at the specified index (exclusive), and working
* backwards from there.
*
* Will fail if i == Integer.MIN_VALUE
*/
static void getChars(int i, int index, char[] buf) {
int q, r;
int charPos = index;
char sign = 0;

// 如果i<0,sign记下它的符号“-”,同时将i转成整数。
if (i < 0) {
sign = '-';
i = -i;
}

// 下面所有的操作也就只针对整数了
// Generate two digits per iteration
while (i >= 65536) {
q = i / 100;
// really: r = i - (q * 100);
r = i - ((q << 6) + (q << 5) + (q << 2));
i = q;
buf [--charPos] = DigitOnes[r];
buf [--charPos] = DigitTens[r];
}

// Fall thru to fast mode for smaller numbers
// assert(i <= 65536, i);
for (;;) {
q = (i * 52429) >>> (16+3);
r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
buf [--charPos] = digits [r];
i = q;
if (i == 0) break;
}
// 最后在判断sign如果不等于零,将 sign 你的值放在char数组的首位buf [--charPos] = sign;
if (sign != 0) {
buf [--charPos] = sign;
}
}
  • i : 被初始化的数字
  • index: 这个数字的长度(包含了负数的符号“-”)
  • buf:字符串容器 - 一个char型数组。

4.3 toString(int i, int radix)

toString(int,int) 第二个参数是表示的进制数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 * <blockquote>
* {@code Integer.toString(n, 16).toUpperCase()}
* </blockquote>
*
* @param i an integer to be converted to a string.
* @param radix the radix to use in the string representation.
* @return a string representation of the argument in the specified radix.
* @see java.lang.Character#MAX_RADIX
* @see java.lang.Character#MIN_RADIX
*/
public static String toString(int i, int radix) {
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
radix = 10;

/* Use the faster version */
if (radix == 10) {
return toString(i);
}

char buf[] = new char[33];
boolean negative = (i < 0);
int charPos = 32;

if (!negative) {
i = -i;
}

while (i <= -radix) {
buf[charPos--] = digits[-(i % radix)];
i = i / radix;
}
buf[charPos] = digits[-i];

if (negative) {
buf[--charPos] = '-';
}

return new String(buf, charPos, (33 - charPos));
}

5. 自动拆箱和装箱

自动拆箱和自动装箱是JDK1.5以后才有的功能,也就是java当中众多的语法糖之一

它的执行时在编译期,会根据代码的语法,在生成class文件的时候,决定是否进行拆箱和装箱的动作。

5.1 自动装箱

我们知道一般创建一个类的对象需要通过 new 关键字,比如:

1
Object obj = new Object();

但是实际上,对于 Integer 类,我们却可以直接这样使用:

1
Integer a = 128;

为什么可以这样,通过反编译工具,我们可以看到,生成的class文件是:

1
Integer a = Integer.valueOf(128);

我们可以看看 valueOf() 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* Returns an {@code Integer} instance representing the specified
* {@code int} value. If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/

public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

其实最后返回的也就是new Integer()产生的对象,但是这里需要注意前面一段代码,当i的值在 -128 <= i < = 127返回的是缓存中的对象,并没有创建一个新的对象,这在通过equals进行比较的时候需要我们注意。

这就是基本数据类型的自动装箱,128是基本数据类型,然后被解析成Integer类。

5.2 自动拆箱

我们将Integer类表示的数据类型赋值给基本数据类型int,就进行了自动拆箱。

1
2
Integer c = new Integer(128);
int m = c;

反编译生成的class文件:

1
2
Integer d = new Integer(128);
m = d.intValue();

简单来讲:

  • 自动装箱就是Integer.valueOf(int i);

  • 自动拆箱就是 i.intValue();

5.3 一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class TestInteger {
public static void main(String[] args) {
Integer i = 10;
Integer j = 10;
System.out.println(i == j);

Integer a = 128;
Integer b = 128;
System.out.println(a == b);


int k = 10;
System.out.println(k == i);
int kk = 128;
System.out.println(kk == a);

Integer m = new Integer(10);
Integer n = new Integer(10);
System.out.println(m == n);
}
}

聪明的你一定能一眼看出答案:

1
2
3
4
5
true
false
true
true
false

我们使用反编译工具Jad,得到的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void main(String args[])
{
Integer i = Integer.valueOf(10);
Integer j = Integer.valueOf(10);
System.out.println(i == j);
Integer a = Integer.valueOf(128);
Integer b = Integer.valueOf(128);
System.out.println(a == b);
int k = 10;
System.out.println(k == i.intValue());
int kk = 128;
System.out.println(kk == a.intValue());
Integer m = new Integer(10);
Integer n = new Integer(10);
System.out.println(m == n);
}

下面我们来看看这中间经历了什么:

首先,

  • 直接声明Integer i = 10,会自动装箱变为Integer i = Integer.valueOf(10);

  • Integer i 会自动拆箱为 i.intValue()。

①、第一个打印结果为 true

对于 i == j ,我们知道这是两个Integer类,他们比较应该是用equals,这里用==比较的是地址,那么结果肯定为false,但是实际上结果为true,这是为什么?

我们进入Integer类的valueOf()底层源码查看:

1
2
3
4
5
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

分析源码我们可以知道在 i >= -128 并且 i <= 127 的时候,第一次声明会将 i 的值放入缓存中,第二次直接取缓存里面的数据,而不是重新创建一个Ingeter 对象。那么第一个打印结果因为 i = 10 在缓存表示范围内,所以为 true。

②、第二个打印结果为 false

从上面的分析我们知道,128是不在-128到127之间的,所以第一次创建对象的时候没有缓存,第二次创建了一个新的Integer对象。故打印结果为false

③、第三个打印结果为 true

Integer 的自动拆箱功能,也就是比较两个基本数据类型,结果当然为true

④、第四个打印结果为 true

解释和第三个一样。int和integer(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比较。

⑤、第五个打印结果为 false

因为这个时候虽然值为10,但是我们通过new关键字来创建的两个对象,是不存在缓存的概念的。两个用new关键字创建的对象用== 来进行比较,结果当然为false。

6. equals(Object obj)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* Compares this object to the specified object. The result is
* {@code true} if and only if the argument is not
* {@code null} and is an {@code Integer} object that
* contains the same {@code int} value as this object.
*
* @param obj the object to compare with.
* @return {@code true} if the objects are the same;
* {@code false} otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}

这个方法很简单,先通过insataceof关键字比较两个对象的关系,然后将对象强转为Integer,再通过自动拆箱,转为两个基本数据的int,然后通过 == 比较。

7. hashCode() 方法

1
2
3
4
5
6
7
8
9
10
11
/**
* Returns a hash code for this {@code Integer}.
*
* @return a hash code value for this object, equal to the
* primitive {@code int} value represented by this
* {@code Integer} object.
*/
@Override
public int hashCode() {
return Integer.hashCode(value);
}

Integer 类的hashCode 方法也比较简单,直接返回其 int 类型的数据。

8. parseInt(String s) 和 parseInt(String s,int radix)方法

toString(int i )是将整型数据转换成字符串类型输出。

parseInt(String s) 能将字符串转换成整型输出。

这两个方法我们在介绍 构造函数 Integer(String s) 时已经详细讲解了。

9. compareTo(Integer anotherInteger)和compare(int x , int y)方法

9.1 compareTo(Integer anotherInteger)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* Compares two {@code Integer} objects numerically.
*
* @param anotherInteger the {@code Integer} to be compared.
* @return the value {@code 0} if this {@code Integer} is
* equal to the argument {@code Integer}; a value less than
* {@code 0} if this {@code Integer} is numerically less
* than the argument {@code Integer}; and a value greater
* than {@code 0} if this {@code Integer} is numerically
* greater than the argument {@code Integer} (signed
* comparison).
* @since 1.2
*/
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}

compareTo方法直接调用内部的conpare方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* Compares two {@code int} values numerically.
* The value returned is identical to what would be returned by:
* <pre>
* Integer.valueOf(x).compareTo(Integer.valueOf(y))
* </pre>
*
* @param x the first {@code int} to compare
* @param y the second {@code int} to compare
* @return the value {@code 0} if {@code x == y};
* a value less than {@code 0} if {@code x < y}; and
* a value greater than {@code 0} if {@code x > y}
* @since 1.7
*/
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

 如果 x < y 返回 -1

 如果 x == y 返回 0

 如果 x > y 返回 1

1
2
3
System.out.println(Integer.compare(1,2)); // -1
System.out.println(Integer.compare(1,1)); // 0
System.out.println(Integer.compare(1,0)); // 1

10. 总结

参考文档:https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html

打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2019-2022 Zhuuu
  • PV: UV:

请我喝杯咖啡吧~

支付宝
微信