java.lang.Number
- 1. Number类介绍
- 2. 子类介绍
- 3. 包装类型
- 3.1. Byte
- 3.2. Short
- 3.3 Integer
- 3.3.1. 静态常量与方法
- 3.3.2. 构造函数
- 3.3.3. 私有类 IntegerCache ,调整数字常量池上限
- 3.4.3. 方法解析
- 3.4.3.1 `String toString(int i, int radix)`
- 3.4.3.2 `String toString(int i)`
- 3.4.3.3 `Integer parseInt(int i, int radix)`
- 3.4.3.4 `Integer parseUnsignedInt(int i, int radix)`
- 3.4.3.4 `Integer valueOf(int i)`
- 3.4.3.4 `Integer getInteger(String nm, int val)`
- 3.4.3.4 `String toUnsignedLong(int i)`
- 3.4.3.4 `int divideUnsigned(int dividend, int divisor)`
- 3.4.3.4 `int remainderUnsigned(int dividend, int divisor)`
- 3.4.3.4 `int highestOneBit(int i)`
- 3.4.3.4 `int lowestOneBit(int i)`
- 3.4.3.4 `int numberOfLeadingZeros(int i)`
- 3.4.3.4 `int numberOfTrailingZeros(int i)`
- 3.4.3.4 `int bitCount(int i)`
- 3.4.3.4 `int rotateLeft(int i, int distance) `
- 3.4.3.4 `int rotateRight(int i, int distance)`
- 3.4.3.4 `int reverse(int i, int distance)`
- 3.4.3.4 `int signum(int i)`
- 3.4.3.4 `int reverseBytes(int i)`
1. Number类介绍
Number
是抽象类,是基本数据类型中数值类型(除char
和boolean
)包装类型、大数值类型和原子操作类型(线程安全)的抽象父类。Number
类中提供的方法如下:
方法名 | 说明 |
---|---|
abstract int intValue() | 抽象方法,子类实现。提供基本类型int 的转换。 |
abstract long longValue() | 抽象方法,子类实现。提供基本类型long 的转换。 |
abstract float floatValue() | 抽象方法,子类实现。提供基本类型float 的转换。 |
abstract double doubleValue() | 抽象方法,子类实现。提供基本类型double 的转换。 |
byte byteValue() | 提供基本类型byte的转换,由int intValue() 强转。 |
short shortValue() | 提供基本类型short的转换,由int intValue() 强转。 |
2. 子类介绍
类全限定名 | 说明 |
---|---|
java.util.concurrent.atomic.AtomicInteger | |
java.util.concurrent.atomic.AtomicLong | |
java.math.BigDecimal | |
java.math.BigInteger | |
java.lang.Byte | 1 字节(8 位)整数 |
java.lang.Double | 双精度浮点数 |
java.util.concurrent.atomic.DoubleAccumulator | |
java.util.concurrent.atomic.DoubleAdder | |
java.lang.Float | 单精度浮点数 |
java.lang.Integer | 4 字节(32 位)整数 |
java.lang.Long | 8 字节(64 位)整数 |
java.util.concurrent.atomic.LongAccumulator | |
java.util.concurrent.atomic.LongAdder | |
java.lang.Short | 2 字节(16 位)整数 |
java.util.concurrent.atomic.Striped64 | 仅包内可见抽象子类, |
3. 包装类型
常用数值的“==”比较
JVM中有数值常量池,存放
[-128, 127]
区间内所有数字。常量池中某个数字被引用时,其所有引用对象地址都相同。
- 基本类型与基本类型比较:值相同,则相同,结果为
true
; - 基本类型与包装类型比较:包装类型自动拆箱,值相同,则相同,结果为
true
; - 包装类型与包装类型比较:
其包装类型为(Byte
、Short
、Integer
、Long
、Float
、Double
,不含父类Number
)- 两包装类型不同时,编译不通过。
- 两包装类型相同时:
- 两个变量均为直接赋值时,如
Integer i1 = ?; Integer i2 = ?;
- 取值在
[-128, 127]
区间内,值相同,则相同,结果为true
; - 取值在
[-128, 127]
区间外,即(-∞, -128) ∪(127, +∞)
,值相同,但对象引用不同,结果为false
; - 强制转换其中之一为基本类型,另外一个比较时包装类型自动拆箱,值相同,则相同,结果为
true
;
- 取值在
- 两个变量其中之一或均使用
new
关键字赋值时,如Integer i1 = new Integer(?); Integer i2 = new Integer(?);
- 任何值相同,但对象引用不同,结果为
false
; - 强制转换其中之一为基本类型,另外一个比较时包装类型自动拆箱,值相同,则相同,结果为
true
;
- 任何值相同,但对象引用不同,结果为
- 两个变量均为直接赋值时,如
示例
public class Main {
public static void main(String[] args) {
int i1 = 9;
int i2 = 9;
System.out.println("基本类型与基本类型比较,结果为" + (i1 == i2));
int i3 = 9;
Integer i4 = 9;
System.out.println("基本类型与包装类型比较,结果为" + (i3 == i4));
int i5 = 9;
Integer i6 = new Integer(9);
System.out.println("基本类型与包装类型比较(使用new关键字):" + (i5 == i6));
Long l7 = 9L;
Integer i8 = 9;
// Error:(37, 52) java: 不可比较的类型: java.lang.Integer和java.lang.Long
// System.out.println("两包装类型不同时,编译不通过。" + (l7 == i8));
Integer i9 = 9;
Integer i10 = 9;
System.out.println("两个变量均为直接赋值时,取值在[-128, 127]区间内,值相同,则相同,结果为" + (i3 == i4));
Integer i11 = 129;
Integer i12 = 129;
System.out.println("两个变量均为直接赋值时,取值在[-128, 127]区间外,即(-∞, -128) ∪(127, +∞),值相同,但对象引用不同,结果为" + (i11 == i12));
Integer i13 = 129;
Integer i14 = 129;
System.out.println("两个变量均为直接赋值时,强制转换其中之一为基本类型,另外一个比较时包装类型自动拆箱,值相同,则相同,结果为" + ((int) i13 == i14));
Integer i15 = 9;
Integer i16 = new Integer(9);
System.out.println("两个变量其中之一或均使用new关键字赋值时,任何值相同,但对象引用不同,结果为" + (i15 == i16));
Integer i17 = new Integer(9);
Integer i18 = new Integer(9);
System.out.println("两个变量其中之一或均使用new关键字赋值时,强制转换其中之一为基本类型,另外一个比较时包装类型自动拆箱,值相同,则相同,结果为" + ((int)i15 == i16));
}
}
结果输出
基本类型与基本类型比较,结果为true
基本类型与包装类型比较,结果为true
基本类型与包装类型比较(使用new关键字):true
// System.out.println("两包装类型不同时,编译不通过。" + (l7 == i8));
两个变量均为直接赋值时,取值在[-128, 127]区间内,值相同,则相同,结果为true
两个变量均为直接赋值时,取值在[-128, 127]区间外,即(-∞, -128) ∪(127, +∞),值相同,但对象引用不同,结果为false
两个变量均为直接赋值时,强制转换其中之一为基本类型,另外一个比较时包装类型自动拆箱,值相同,则相同,结果为true
两个变量其中之一或均使用new关键字赋值时,任何值相同,但对象引用不同,结果为false
两个变量其中之一或均使用new关键字赋值时,强制转换其中之一为基本类型,另外一个比较时包装类型自动拆箱,值相同,则相同,结果为true
与或运算符
与
简单理解,将1
和0
看做true
和false
,执行与运算时,若两个都为true
,结果为true
,若其中一个为false
,则结果为false
。那么1
和0
的与运算结果为:
0 & 0 = 0;
0 & 1 = 0;
1 & 0 = 0;
1 & 1 = 1;
或
执行或运算时,若两个都为false
,结果为false
,若其中一个为true
,则结果为true
。那么1
和0
的与运算结果为:
0 & 0 = 0;
0 & 1 = 1;
1 & 0 = 1;
1 & 1 = 1;
原码、反码、补码
- 原码即数字本身的二进制码,最高位(最左第一位)为符号位,最高位为
0
表示正数,为1
表示负数,其余位才是数值的大小。 - 反码
- 正数的反码与原码相同;
- 负数的反码则是对原码取反,符号位不变(保持为
1
)。
- 补码
- 正数的补码与原码相同;
- 负数的补码则是反码加
1
。
原反补小练
int i = 293;
System.out.println((byte) i); --> 37
取i
的二进制数0001 0010 0101
,得293
的二进制数占9
位,超byte
约定的8
位,因此取原码为0010 0101
。原码最高位为0
,即正数。则反码和补码均为0010 0101
,转换0010 0101
为10
进制得37
。
int i = 135;
System.out.println((byte) i); --> -121
取i
的二进制数1000 0111
,取原码为1000 0111
。原码最高位为1
,即负数。则
反码为1111 1000
补码为1111 1000 + 1
= 1111 1001
补码最高位丢弃,得0111 1001
,转10
进制为121
,因其为负数,则结果为-121
。
3.1. Byte
最小数值类型,占用内存一个字节(每字节8
位),默认值为零,取值区间为[-128, 127]
,即[-2^7, 2^7 - 1]
。JVM中有数值常量池,存放[-128, 127]
区间内所有数字,即Byte
的所有值均为常量池中取出。Byte
实现java.lang.Comparable
接口,提供比较和排序方法。
3.1.1. 静态常量与方法
常量或方法 | 说明 |
---|---|
TYPE | 返回基本类型的Class,byte.class |
SIZE | 返回Byte 位数,取值为8 |
BYTES | 返回Byte 占用字节数,取值为1 ,方法实现为SIZE / Byte.SIZE |
String toString(byte b) | 将某个byte 以10 进制的形式转换为字符串,方法实现为Integer.toString((int)b, 10); |
int hashCode(byte value) | 将value 强转为int 类型,并作为hashCode 返回 |
byte parseByte(String s, int radix) | 将某个字符串s 以指定进制radix 的形式解析为byte ,方法检查该字符串为[-128, 127] 区间上的数字,否则抛出java.lang.NumberFormatException 异常 |
byte parseByte(String s) | 将某个字符串s 以10 进制的形式解析为byte ,方法检查该字符串为[-128, 127] 区间上的数字,否则抛出java.lang.NumberFormatException 异常 |
Byte valueOf(byte b) | 将某个byte 转换为包装类型Byte ,方法实现为从ByteCahe 缓存里取出对应索引的数字ByteCache.cache[(int)b + 128] |
Byte valueOf(String s, int radix) | 将某个字符串s 以指定进制radix 的形式解析为byte ,方法检查该字符串为[-128, 127] 区间上的数字,否则抛出java.lang.NumberFormatException 异常 |
byte valueOf(String s) | 将某个字符串s 以10 进制的形式解析为byte ,方法检查该字符串为[-128, 127] 区间上的数字,否则抛出java.lang.NumberFormatException 异常 |
Byte decode(String nm) | 解码某个数字字符串nm 为Byte ,程序将根据数字字符串实际内容判断用何种进制(8 、10 、16 )来解析该字符串。方法检查该字符串为-128 ~ 127 之间的数字,否则抛出java.lang.NumberFormatException 异常 |
int compare(byte x, byte y) | 比较两个byte ,x 与y 之间的大小,方法实现为取两者差值x - y; |
int toUnsignedInt(byte x) | 将byte 转换为无符号的int 类型。方法实现为((int) x) & 0xff |
long toUnsignedLong(byte x) | 将byte 转换为无符号的long 类型。方法实现为((long) x) & 0xff |
3.1.2. 构造函数
构造函数 | 说明 |
---|---|
Byte(byte value) | 接收基本类型byte 作为值,新建包装类型Byte 实例 |
Byte(String s) | 接收数字字符串s ,并将其以10 进制的形式解析为包装类型Byte 实例 |
3.1.3. 私有类 ByteCache
ByteCache
是Byte.java
类中的字节缓存类,采用一个长度为256
的Byte
数组缓存[-128, 127]
区间内所有数字。
private static class ByteCache {
private ByteCache(){}
static final Byte cache[] = new Byte[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Byte((byte)(i - 128));
}
}
3.2. Short
占用内存两个字节(每字节8
位,共16
位),默认值为零,取值区间为[-32768, 32767]
,即[-2^15, 2^15 - 1]
。Short
实现java.lang.Comparable
接口,提供比较和排序方法。
3.2.1. 静态常量与方法
常量或方法 | 说明 |
---|---|
TYPE | 返回基本类型的Class,short.class |
SIZE | 返回Short 位数,取值为16 |
BYTES | 返回Short 占用字节数,取值为2 ,方法实现为SIZE / Byte.SIZE |
String toString(short s) | 将某个short 以10 进制的形式转换为字符串,方法实现为Integer.toString((int)s, 10); |
int hashCode(short value) | 将value 强转为int 类型,并作为hashCode 返回 |
Short parseShort(String s) | 将某个字符串s 以10 进制的形式解析为short ,方法检查该字符串为[-32768, 32767] 区间上的数字,否则抛出java.lang.NumberFormatException 异常 |
byte parseShort(String s, int radix) | 将某个字符串s 以指定进制radix 的形式解析为short ,方法检查该字符串为[-32768, 32767] 区间上的数字,否则抛出java.lang.NumberFormatException 异常 |
Short valueOf(short s) | 将某个short 转换为包装类型Short ,若s 取值在[-32768, 32767] 区间,则从ShortCache 缓存里取出对应索引的数字ShortCache.cache[(int)b + 128] ,否则返回new Short(s) |
Short valueOf(String s, int radix) | 将某个字符串s 以指定进制radix 的形式解析为Short ,方法检查该字符串为[-32768, 32767] 区间上的数字,否则抛出java.lang.NumberFormatException 异常 |
Short valueOf(String s) | 将某个字符串s 以10 进制的形式解析为Short ,方法检查该字符串为[-32768, 32767] 区间上的数字,否则抛出java.lang.NumberFormatException 异常 |
Short decode(String nm) | 解码某个数字字符串nm 为Short ,程序将根据数字字符串实际内容判断用何种进制(8 、10 、16 )来解析该字符串。方法检查该字符串为[-32768, 32767] 区间上的数字,否则抛出java.lang.NumberFormatException 异常 |
int compare(short x, short y) | 比较两个short ,x 与y 之间的大小,方法实现为取两者差值x - y; |
short reverseBytes(short i) | 反转short 的字节,非将数字反转,而是反转字节(按8 位一组反转),方法实现为(short) (((i & 0xFF00) >> 8) | (i << 8)) |
int toUnsignedInt(short x) | 将short 转换为无符号的int 类型。方法实现为((int) x) & 0xffff |
long toUnsignedLong(short x) | 将short 转换为无符号的int 类型。方法实现为((int) x) & 0xffff |
3.2.2. 构造函数
构造函数 | 说明 |
---|---|
Short(short value) | 接收基本类型short 作为值,新建包装类型Short 实例 |
Short(String s) | 接收数字字符串s ,并将其以10 进制的形式解析为包装类型Short 实例 |
3.2.3. 私有类 ShortCache
ShortCache
是Short.java
类中的字节缓存类,采用一个长度为256
的Short
数组缓存[-128, 127]
区间内所有数字。JVM中有数值常量池,存放[-128, 127]
区间内所有数字,即Short
的所有值在[-128, 127]
区间上的均从常量池中取出。
private static class ShortCache {
private ShortCache(){}
static final Short cache[] = new Short[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Short((short)(i - 128));
}
}
3.2.4. 方法解析
3.2.4.1 short reverseBytes(short i)
该方法具体实现为(short) (((i & 0xFF00) >> 8) | (i << 8))
,是将short
数字按8
位一组进行反转。
(short) (((i & 0xFF00) >> 8) | (i << 8))
0xFF00
是16
进制数,其10
进制和2
进制分别为65280
和1111 1111 0000 0000
,而与操作&
则是当0xFF00
与上i
时,将0 - 0
、0 - 1
或1 - 0
对应位置的数清零,将1 - 1
对应位置的1
保留。>> 8
则是将(i & 0xFF00)
的结果右移8
位,然后或上i
左移8
位的结果(i << 8)
。
以100
为例
Short.reverseBytes((short)100); --> 25600
100
用二进制表示形式为0110 0100
,16
位则是0000 0000 0110 0100
。
步骤 | 原式 | 解析 | 结果 | 十进制结果 |
---|---|---|---|---|
1 | 100 & 0xFF00 | 0000 0000 0110 0100 & 1111 1111 0000 0000 | 0000 0000 0000 0000 | 0 |
2 | (100 & 0xFF00) >> 8 | 0000 0000 0000 0000 >> 8 | 0000 0000 0000 0000 | 0 |
3 | 100 << 8 | 0000 0000 0110 0100 << 8 | 0110 0100 0000 0000 | 25600 |
4 | (100 & 0xFF00) >> 8 | i << 8 | 0110 0100 0000 0000 | 0000 0000 0000 0000 | 0110 0100 0000 0000 | 25600 |
而通常来说将0000 0000 0110 0100
按8
位一组反转后得到0110 0100 0000 0000
得10
进制数25600
也比较直观。
但若是一个比较特殊的数呢?
以1234
为例
Short.reverseBytes((short)1234); --> -11772
1234
用二进制表示形式为0100 1101 0010
,16
位则是0000 0100 1101 0010
。
步骤 | 原式 | 解析 | 结果 | 十进制结果 |
---|---|---|---|---|
1 | 1234 & 0xFF00 | 0000 0100 1101 0010 & 1111 1111 0000 0000 | 0000 0100 0000 0000 | 1024 |
2 | (1234 & 0xFF00) >> 8 | 0000 0100 0000 0000 >> 8 | 0000 0000 0000 0100 | 4 |
3 | 1234 << 8 | 0000 0100 1101 0010 << 8 | 0100 1101 0010 0000 0000 | 315904 |
4 | (1234 & 0xFF00) >> 8 | i << 8 | 0000 0000 0000 0100 | 0100 1101 0010 0000 0000 | 0100 1101 0010 0000 0100 | 315908 |
5 | (short)(1234 & 0xFF00) >> 8 | i << 8 | - | - | -11772 |
315908
这个数已经超出[-32768, 32767]
区间了,很明显强转类型为short
会丢失精度。那么就要根据二进制原码、反码、补码来计算315908
被强转之后的值,按照之前了解的原码、反码和补码的定义。
已知315908
的二进制数为0100 1101 0010 0000 0100
,强转short
须截取16
位的数得原码1101 0010 0000 0100
。
由于原码第一位为1
,表示为负数。需要先计算反码然后得出补码。
原码为1101 0010 0000 0100
反码为1010 1101 1111 1011
补码为1010 1101 1111 1011 + 1
= 1010 1101 1111 1100
补码最高位丢弃,得0010 1101 1111 1100
,转10
进制为11772
,因其为负数,则结果为-11772
。
3.3 Integer
占用内存四个字节(每字节8
位,共32
位),默认值为零,取值区间为[-2147483648, 2147483647]
,即[-2^31, 2^31 - 1]
,分别用16
进制数0x80000000
和0x7fffffff
表示。Integer
实现java.lang.Comparable
接口,提供比较和排序方法。
3.3.1. 静态常量与方法
常量或方法 | 说明 |
---|---|
TYPE | 返回基本类型的Class,int.class |
SIZE | 返回Byte 位数,取值为32 |
BYTES | 返回Byte 占用字节数,取值为4 ,方法实现为SIZE / Byte.SIZE |
String toString(int i, int radix) | 将某个int 以指定进制的形式转换为字符串 |
String toString(int i) | 将某个int 以10 进制的形式转换为字符串 |
int hashCode(int value) | 将value 强转为int 类型,并作为hashCode 返回 |
int parseInt(String s) | 将某个字符串s 以10 进制的形式解析为int |
int parseInt(String s, int radix) | 将某个字符串s 以指定进制radix 的形式解析为int |
int parseUnsignedInt(String s) | 将某个字符串s 以10 进制radix 的形式解析为无符号的int |
int parseUnsignedInt(String s, int radix) | 将某个字符串s 以指定进制radix 的形式解析为无符号的int |
Integer valueOf(String s) | 将某个字符串s 以10进制radix 的形式解析为包装类型Integer |
Integer valueOf(String s, int radix) | 将某个字符串s 以指定进制radix 的形式解析为包装类型Integer ,方法实现为Integer.valueOf(parseInt(s,radix)) |
Integer valueOf(int i) | 将int 数字转换为包装类型Integer |
Integer getInteger(String nm) | 从系统属性中获取指定属性名称nm 对应的值,并解码为Integer ,若未找到该值或解码失败,则返回null |
Integer getInteger(String nm, int val) | 从系统属性中获取指定属性名称nm 对应的值,并解码为Integer ,若未找到该值或解码失败,则返回传入的包装类型的默认值val |
Integer getInteger(String nm, Integer val) | 从系统属性中获取指定属性名称nm 对应的值,并解码为Integer ,若未找到该值或解码失败,则返回传入的默认值val |
Integer decode(String nm) | 解码某个数字字符串nm 为Integer ,程序将根据数字字符串实际内容判断用何种进制(8 、10 、16 )来解析该字符串 |
int compare(int x, int y) | 比较两个int ,x 与y 之间的大小,与short 不同,方法只会返回1, 0, -1 。方法实现为(x < y) ? -1 : ((x == y) ? 0 : 1) |
int compareUnsigned(int x, int y) | 比较两个int ,x 与y 之间的大小,方法实现为compare(x + MIN_VALUE, y + MIN_VALUE) |
long toUnsignedLong(int i) | 将int 转换为无符号的long ,方法实现为((long) x) & 0xffffffffL |
int divideUnsigned(int dividend, int divisor) | 将传入的两个数转换为无符号的long 后相除,再强转回int 返回。方法实现为(int)(toUnsignedLong(dividend) / toUnsignedLong(divisor)) |
int remainderUnsigned(int dividend, int divisor) | 将传入的两个数转换为无符号的long 后求余,再强转回int 返回。方法实现为(int)(toUnsignedLong(dividend) / toUnsignedLong(divisor)) |
int highestOneBit(int i) | 求最高位权值,将i 的二进制数除最高位外的所有数1 替换为0 后转为int 返回。该方法总是返回2 的n 次方,n ∈ Z ,0的权值总为0 |
int lowestOneBit(int i) | 求最低位权值,将i 的二进制数除最低位外的所有数1 替换为0 后转为int 返回。该方法总是返回2 的n 次方,n ∈ Z ,0的权值总为0。方法实现为i & -i |
int numberOfLeadingZeros(int i) | 返回i 的二进制数中,最高位前0 的数量,总位数(int 的位数为32 ),即从左往右数,遇到第一个数字1 后停下所得到的数量(不含1 ),数字0 的数量总为32 ,负数因其表现形式为最高位前的数全是1 ,所以负数的最高位前0 的数量总为0 |
int numberOfTrailingZeros(int i) | 返回i 的二进制数中,最低位开始连续为0 的数量,即从右往左数,遇到第一个数字1 后停下所得到的数量(不含1 ),数字0 的数量总为32 ,绝对值相同的正负数的数量相同 |
int bitCount(int i) | 返回i 的二进制中,各位数为1 的总数量,0 的总数量总是为0 ,负数因其表现形式为最高位前的数全是1 ,所以这些为1 的数也会算上 |
int rotateLeft(int i, int distance) | 左旋,方法实现为(i << distance) | (i >>> -distance) |
int rotateRight(int i, int distance) | 右旋,方法实现为(i >>> distance) | (i << -distance) |
int reverse(int i, int distance) | 反转 |
int signum(int i) | 判断正负数,负数返回-1 ,正数返回0 ,零总是返回0 ,方法实现为(i >> 31) | (-i >>> 31) |
int reverseBytes(int i) | 按字节反转,方法实现为((i >>> 24)) | ((i >> 8) & 0xFF00) | ((i << 8) & 0xFF0000) | ((i << 24)) |
int sum(int a, int b) | 求和。方法实现为a + b ,可用于Lambda 表达式Integer::sum |
int max(int a, int b) | 返回两个数中,比较大的一个。方法实现为Math.max(a, b) ,可用于Lambda 表达式Integer::max |
int min(int a, int b) | 返回两个数中,比较大的一个。方法实现为Math.min(a, b) ,可用于Lambda 表达式Integer::max |
String toBinaryString(int i) | 将int 转换为32 位长度的二进制字符串,负数的最高位前会填充1 。方法实现为toUnsignedString0(i, 1) |
String toOctalString(int i) | 将int 转换为八进制字符串。方法实现为toUnsignedString0(i, 3) |
String toHexString(int i) | 将int 转换为十六进制字符串。方法实现为toUnsignedString0(i, 4) |
String toUnsignedString(int i) | 将int 转换为无符号long 后再输出为字符串。方法实现为Long.toUnsignedString(toUnsignedLong(i)) |
String toUnsignedString(int i, int radix) | 将int 转换为无符号long 后再输出为指定进制数的字符串。方法实现为Long.toUnsignedString(toUnsignedLong(i), radix) |
3.3.2. 构造函数
构造函数 | 说明 |
---|---|
Integer(int value) | 接收基本类型int 作为值,新建包装类型Integer 实例 |
Integer(String s) | 接收数字字符串s ,并将其以10 进制的形式解析为包装类型Integer 实例 |
3.3.3. 私有类 IntegerCache ,调整数字常量池上限
IntegerCache
是Integer.java
类中的数值缓存类,同样也是采用一个长度为256
的Integer
数组缓存[-128, 127]
区间内所有数字,但它与Byte
、Short
不同的是,JDK提供通过设置虚拟机参数java.lang.Integer.IntegerCache.high
来调整常量池中的最大值。
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
java.lang.Integer.IntegerCache.high
先在IDEA中设置JVM参数,-Djava.lang.Integer.IntegerCache.high=400
Integer i1 = 399;
Integer i2 = 399;
System.out.println(i1 == i2); --> true
结果如常用数值的“==”比较中描述的
两个变量均为直接赋值时,取值在[-128, 127]区间内,值相同,则相同,结果为true
两个变量均为直接赋值时,取值在[-128, 127]区间外,即(-∞, -128) ∪(127, +∞),值相同,但对象引用不同,结果为false
取值区间将被调整至
在[-128, 400]区间内,值相同,则相同,结果为true
在[-128, 400]区间外,即(-∞, -128) ∪(400, +∞),值相同,但对象引用不同,结果为false
3.4.3. 方法解析
3.4.3.1 String toString(int i, int radix)
Byte
和Short
类中的toString(?)
方法均由此方法实现。其代码如
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));
}
- 检查其进制数是否属于
[2, 36]
区间,若不属于,则默认转换进制数设置为10
; - 若进制数为
10
,调用String toString(int i)
,见下文; - 检查传入数字
i
是否负数,若非负数,则转换为负数; - 进入
while
循环,按-(i % radix)
获取下标,并从常量数组digits
中取得对应字符,然后i = i / radix
;
第4
步比较笼统,所以先来复习下10
进制转其他进制的算法
十进制转二进制
,先取十进制数x
余2
的结果,在依次将x
除以2
(取整并舍弃小数点,直至其小于2
)后余2
,记录其结果最后倒排该结果,得二进制。以333
为例
步骤 | 十进制数 | 除以2 | 余2 |
---|---|---|---|
1 | 333 | - | 1 |
2 | 333 | 166 | 0 |
3 | 166 | 83 | 1 |
4 | 83 | 41 | 1 |
5 | 41 | 20 | 0 |
6 | 20 | 10 | 0 |
7 | 10 | 5 | 1 |
8 | 5 | 2 | 0 |
9 | 2 | 1 | 1 |
倒排后得二进制结果:1 0100 1101
十进制转八进制
,先取十进制数x
余8
的结果,在依次将x
除以8
(取整并舍弃小数点,直至其小于8
)后余8
,记录其结果,最后倒排该结果,得八进制。以333
为例
步骤 | 十进制数 | 除以8 | 余8 |
---|---|---|---|
1 | 333 | - | 5 |
2 | 333 | 41 | 1 |
3 | 41 | 5 | 5 |
倒排后得八进制结果:515
十进制转十六进制
,先取十进制数x
余16
的结果,再依次将x
除以16
(取整并舍弃小数点,直至其小于16
)后余16
,记录其结果,最后倒排该结果,得十六进制。以333
为例
步骤 | 十进制数 | 除以16 | 余16 |
---|---|---|---|
1 | 333 | - | 13(d) |
2 | 333 | 20 | 4 |
3 | 20 | 1 | 1 |
倒排后得十六进制结果:14d
根据以上过程能发现规律:先取十进制数x
余进制数的结果,再依次将x
除以进制数(取整并舍弃小数点,直至其小于进制数)后余进制数,记录结果。当十进制数x
通过除以进制数至小于进制数并求余后,不再执行下一步被除求余的操作,接着倒排结果,得到进制数对应值。
简单编写一段代码来计算十进制转其它进制的字符串
首先要看下Integer
类中提供的常量数组digits
,它保证[0, 36)
区间内,能够通过下标取得对应的值,如十六进制的10
对应a
、三十六进制的35
对应z
。之所以会有z
,是因为Java
支持2 ~ 36
进制的转换。
final static char[] digits = {
'0' , '1' , '2' , '3' , '4' , '5' ,
'6' , '7' , '8' , '9' , 'a' , 'b' ,
'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
'o' , 'p' , 'q' , 'r' , 's' , 't' ,
'u' , 'v' , 'w' , 'x' , 'y' , 'z'
};
public static String toString(int i, int radix) {
boolean negative = (i < 0);
if (negative) {
i = -i;
}
StringBuilder stringBuilder = new StringBuilder(33);
stringBuilder.append(digits[i % radix]);
while (i >= radix) {
i = i / radix;
stringBuilder.append(digits[i % radix]);
}
if(negative) {
stringBuilder.append("-");
}
return stringBuilder.reverse().toString();
}
上述代码就是逐步记录十进制数i
除以进制数并余进制数后的结果,最后通过StringBuilder.reverse()
方法反转字符串得到进制数对应字符串值。对比JDK中的源码,除了一个正数循环和另一个负数循环以外似乎没有其它差异,毕竟StringBuilder
也是可以替换成char[]
来实现的。
3.4.3.2 String toString(int i)
将数字i
以10
进制形式转换为字符串,由于日常使用中,int
类型数字总为10
进制,因此该方法是否真的有意义值得推敲,且实现代码复杂。
在单线程一亿个数循环转换测试中发现i + ""
转字符串消耗的时间比Integer.toString(i)
少200 ~ 600毫秒甚至更多
,因此推荐使用i + ""
的方式将数字转换成十进制字符串,而不是Integer.toString(i)
。
当然其中的移位运算值得一看。
static void getChars(int i, int index, char[] buf) {
int q, r;
int charPos = index;
char sign = 0;
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;
}
if (sign != 0) {
buf [--charPos] = sign;
}
}
String str = null;
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
str = i + "";
}
System.out.println(System.currentTimeMillis() - startTime);
startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
str = Integer.toString(i);
}
--------------------------------------- 待续 -------------------------