前言
在解释toString()方法之前,我们先来了解下如何将十进制整数转换成其他进制。
将十进制整数转换成其他进制的方法是:整数转换为r进制数时,采用除r取余方法,即将十进制整数不断除以r取余数,直到商为0,所得的余数按逆序排列。
图解:
用Java简单来实现这个代码:
public class Test {
public static void main(String[] args) {
System.out.println(Integer.toString(123456, 2));// 11110001001000000
System.out.println(toString(123456, 2));// 11110001001000000
}
public static String toString(int i, int radix) {
// 用StringBuilder来存储每个字符
StringBuilder sb = new StringBuilder();
while (i > 0) {
sb.append(i % radix);
i /= radix;
}
// 将结果逆序返回
return sb.reverse().toString();
}
}
注意,上面的代码只能处理十进制及以下的进制转换,如果是十进制以上的进制转换则不会成功,因为超过十进制,那么所表示的数如12、14等都需要用两个数来表示,而不是一个。
public static void main(String[] args) {
System.out.println(Integer.toString(123456, 16));// 1e240
System.out.println(toString(123456, 16));// 141240
}
所以我们在实际中引入了英文字母A~Z来表示十之后的数字,如用'A'表示十进制数字10、'F'表示十进制数字15等。
而我们知道数字0~9有10个,A~Z有26个,所以可以表示36个数码,表示出三十六进制。
/*
radix=[2, 36]
当radix=2时表示二进制,数码有0,1
对应的十进制数是0,1
当radix=3时表示三进制,数码有0,1,2
对应的十进制数是0,1,2
当radix=4时表示四进制,数码有0,1,2,3
对应的十进制数是0,1,2,3
当radix=5时表示五进制,数码有0,1,2,3,4
对应的十进制数是0,1,2,3,4
当radix=6时表示六进制,数码有0,1,2,3,4,5
对应的十进制数是0,1,2,3,4,5
当radix=7时表示七进制,数码有0,1,2,3,4,5,6
对应的十进制数是0,1,2,3,4,5,6
当radix=8时表示八进制,数码有0,1,2,3,4,5,6,7
对应的十进制数是0,1,2,3,4,5,6,7
当radix=9时表示九进制,数码有0,1,2,3,4,5,6,7,8
对应的十进制数是0,1,2,3,4,5,6,7,8
当radix=10时表示十进制,数码有0,1,2,3,4,5,6,7,8,9
对应的十进制数是0,1,2,3,4,5,6,7,8,9
当radix=11时表示十一进制,数码有0,1,2,3,4,5,6,7,8,9,A
对应的十进制数是0,1,2,3,4,5,6,7,8,9,10
当radix=12时表示十二进制,数码有0,1,2,3,4,5,6,7,8,9,A,B
对应的十进制数是0,1,2,3,4,5,6,7,8,9,10,11
当radix=13时表示十三进制,数码有0,1,2,3,4,5,6,7,8,9,A,B,C
对应的十进制数是0,1,2,3,4,5,6,7,8,9,10,11,12
当radix=14时表示十四进制,数码有0,1,2,3,4,5,6,7,8,9,A, B, C, D
对应的十进制数是0,1,2,3,4,5,6,7,8,9,10,11,12,13
当radix=15时表示十五进制,数码有0,1,2,3,4,5,6,7,8,9,A, B, C, D, E
对应的十进制数是0,1,2,3,4,5,6,7,8,9,10,11,12,13,14
当radix=16时表示十六进制,数码有0,1,2,3,4,5,6,7,8,9,A, B, C, D, E, F
对应的十进制数是0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
当radix=17时表示十七进制,数码有0,1,2,3,4,5,6,7,8,9,A, B, C, D, E, F, G
对应的十进制数是0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
当radix=18时表示十八进制,数码有0,1,2,3,4,5,6,7,8,9,A, B, C, D, E, F, G, H
对应的十进制数是0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17
当radix=19时表示十九进制,数码有0,1,2,3,4,5,6,7,8,9,A, B, C, D, E, F, G, H, I
对应的十进制数是0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18
当radix=20时表示二十进制,数码有0,1,2,3,4,5,6,7,8,9,A, B, C, D, E, F, G, H, I, J
对应的十进制数是0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19
当radix=21时表示二十一进制,数码有0,1,2,3,4,5,6,7,8,9,A, B, C, D, E, F, G, H, I, J, K
对应的十进制数是0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
当radix=22时表示二十二进制,数码有0,1,2,3,4,5,6,7,8,9,A, B, C, D, E, F, G, H, I, J, K, L
对应的十进制数是0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21
当radix=23时表示二十三进制,数码有0,1,2,3,4,5,6,7,8,9,A, B, C, D, E, F, G, H, I, J, K, L, M
对应的十进制数是0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22
当radix=24时表示二十四进制,数码有0,1,2,3,4,5,6,7,8,9,A, B, C, D, E, F, G, H, I, J, K, L, M, N
对应的十进制数是0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23
当radix=25时表示二十五进制,数码有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
对应的十进制数是0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24
当radix=26时表示二十六进制,数码有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
对应的十进制数是0,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
当radix=27时表示二十七进制,数码有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
对应的十进制数是0,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
当radix=28时表示二十八进制,数码有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
对应的十进制数是0,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
当radix=29时表示二十九进制,数码有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
对应的十进制数是0,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
当radix=30时表示三十进制,数码有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
对应的十进制数是0,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
当radix=31时表示三十一进制,数码有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
对应的十进制数是0,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
当radix=32时表示三十二进制,数码有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
对应的十进制数是0,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
当radix=33时表示三十三进制,数码有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
对应的十进制数是0,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
当radix=34时表示三十四进制,数码有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
对应的十进制数是0,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
当radix=35时表示三十五进制,数码有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
对应的十进制数是0,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
当radix=36时表示三十六进制,数码有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
对应的十进制数是0,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映射到'Z',使用了digits字符数组。
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'
};
该数组的索引下标所表示的十进制数正好对应它能表示的数码。
所以我们修改代码,添加digits数组,如下:
public class Test {
public static void main(String[] args) {
System.out.println(Integer.toString(123456, 16));// 1e240
System.out.println(toString(123456, 16));// 1e240
System.out.println(Integer.toString(987654, 23));// 3c40b
System.out.println(toString(987654, 23));// 3c40b
}
public static String toString(int i, int radix) {
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'
};
StringBuilder sb = new StringBuilder();
while (i > 0) {
sb.append(digits[i % radix]);
i /= radix;
}
return sb.reverse().toString();
}
}
toString(int)
Integer类的toString()方法有两个重载方法。
toString(int i)方法是将int类型的数值以十进制的形式输出,实现该方法的算法是将十进制数中的每一位数字放到字符数组中,然后将字符数组转换成字符串进行返回。
/**
* 将int类型的数值i转换成十进制的字符串形式返回
*
* @param i 一个int类型的数值
* @return 以10为底的自变量的字符串表示形式
*/
public static String toString(int i) {
// 如果当前参数i直接等于Integer类型所能表示的最小值
// 为什么要有这个判断?因为将-2147483648的值直接返回的原因就是整数最大只能表示2147483647,无法将stringSize(-i)中的i赋值成-2147483648。
if (i == Integer.MIN_VALUE)
// 那么直接返回最小值字符串即可
return "-2147483648";
// 调用stringSize()方法获取整数的数字位数,如果是负数则加个负号强制转换成正数
// 并且stringSize()方法必须传入一个正整数才能计算数字位数
// 如果是i是负数则调用stringSize(-i) + 1,会把负号计算在内,例如-123得到的值是4位
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
// 创建一个size长度的字符数组,用来按序存放数字中的每一位
char[] buf = new char[size];
// 调用getChars()方法为buf字符数组填充内容,填充的内容就是i的每一位数字(如果是负号,则包括符号位)
getChars(i, size, buf);
// 然后将字符数组转换成字符串返回
return new String(buf, true);
}
toString(int, int)
该方法就是将指定整数以指定进制的字符串形式进行返回,例如toString(10, 2)就会将整数10以2进制形式的字符串返回。
该方法的核心算法就是前言所提到的计算整数转换成其他进制的方法,也是将每一个字符放到字符数组中然后转换成字符串形式返回。
/**
* 返回第二个参数指定的基数中第一个参数的字符串表示形式。
* 如果基数小于Character.MIN_RADIX或大于Character.MAX_RADIX ,则使用基数10 。
* 如果第一个参数为负,则结果的第一个元素是 ASCII 减号字符'-' ( '\u002D' )。 如果第一个参数不是负数,则结果中不会出现符号字符。
* 结果的其余字符表示第一个参数的大小。 如果幅度为零,则由单个零字符'0' ( '\u0030' ) 表示; 否则,幅度表示的第一个字符将不是零字符。 以下 ASCII 字符用作数字:0123456789abcdefghijklmnopqrstuvwxyz
* 它们是'\u0030'到'\u0039'和'\u0061'到'\u007A' 。 如果radix为N ,则这些字符的前N 个将按所示顺序用作基数-N数字。 因此,十六进制(基数 16)的数字是0123456789abcdef 。 如果需要大写字母,可以对结果调用String.toUpperCase()方法:Integer.toString(n, 16).toUpperCase()
* 例如:Integer.toString(10,2)的返回结果是"1010",表示将十进制数字10转换成二进制字符串返回
* 例如:Integer.toString(16,8)的返回结果是"20",表示将十进制数字16转换成八进制字符串返回
*
* @param i 要转换为字符串的整数
* @param radix 在字符串表示中使用的基数(进制)
* @return 指定基数(进制)中参数的字符串表示形式
*/
public static String toString(int i, int radix) {
// Character.MIN_RADIX=2;Character.MAX_RADIX=36
// 即输入参数radix的有效范围应该是[2, 36]
// 但如果输入[2, 36]范围之外的radix,那么会自动当作radix=10来处理
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
radix = 10;
// 使用更快的版本,即如果传入的radix参数为10,直接调用toString()的重载方法,不再进行下面的操作
if (radix == 10) {
return toString(i);
}
// 创建一个长度为33的字符数组,为什么是33呢,因为一个int类型的数据最多是32位二进制,如果算上符号那么最多可以有33的字符
char buf[] = new char[33];
// 局部变量,记录是否是负数的标志,如果i是负数则negative为true,如果i是正数或0则negative为false
boolean negative = (i < 0);
// 指向buf数组中元素的指针,初始值指向数组中最后一个元素
int charPos = 32;
// 如果传入的参数i是一个正数,则转换成负数,当作负数来处理更加方便
if (!negative) {
i = -i;// 将正数转换成负数
}
/* 核心代码 start */
// 将整数转换为r进制数时,采用除r取余方法,即将十进制整数不断除以r取余数,直到商为0,所得的余数按逆序排列
while (i <= -radix) {
// 倒序保存字符
buf[charPos--] = digits[-(i % radix)];// 因为是将i作为负数来处理,所以前面再添加一个"-"号转换成正数,来作为数组下标索引
// 不断除以r取余数,直到商为0
i = i / radix;
}
buf[charPos] = digits[-i];
/* 核心代码 end */
// 对是否要为字符串添加负号"-"作判断,如果negative标志为true表示是负数则添加"-"号
if (negative) {
buf[--charPos] = '-';
}
// 将字符数组中的有效字符拼接成字符串返回
return new String(buf, charPos, (33 - charPos));
}