面试官让你手写进制转换?看看JDK的大神是怎么写的!

想起前段时间在做算法题的时候,评论区里看到一条有趣的评论,原文是这样的:“别看现在讨论区里各种秀优化,等到真正面试的时候,面试官让你手写个进制转换你都得慌张

哈哈,确实,平时做算法,考虑各种方法,想办法提高效率,降低空间的消耗,但实际真正面试的时候,可能情急之下还是只会拿出自己最熟悉的做法。

看到进制转换,我不禁也惊了一下,要我短时间内写出非常完美的代码,肯定也是为难的,而且一不留神,就会降低效率,增加空间的消耗,所以,我发现,这确实是个值得好好探究的问题。

谈到进制转换,第一印象是什么,反正我当时脑子里第一想的是栈,而且也只是一个模模糊糊的思路,感觉很急的情况下,难免会出现一些错误。

先不慌,我们看下JDK的大神们,是怎样写的。

假设进制转换的原理大家都非常清楚了哦 ~ 不清楚的百度一下啦 ~


JDK11-Integer-toString方法

Integer类中有一个静态方法:toString,其主要的作用就是进制转换,看看它到底有何神奇之处~~~

  • 注释为个人所写。
	/**注释:ATFWUS
     * 说明:返回用第二个参数指定基数表示的第一个参数的字符串表示形式。
     * @param i 待转换的十进制数
     * @param radix 基数
     * @return String
     */
    public static String toString(int i, int radix) {
        //如果基数小于 `Character.MIN_RADIX`(2) 或者大于 `Character.MAX_RADIX`(36),则改用基数 10。
        **if (radix < 2 || radix > 36) {
            radix = 10;
        }
        //基数等于10直接调用toString方法
        if (radix == 10) {
                return toString(i);
        } else if (!String.COMPACT_STRINGS) {
            return toStringUTF16(i, radix);//采用UTF16编码的转换
        } else {
            //buf数组存储转换后的结果
            byte[] buf = new byte[33];
            boolean negative = i < 0;
            int charPos = 32;
            //如果i大于0,也先转换成负数,便于后续的转换
            if (!negative) {
                i = -i;
            }
            //进制转换核心代码,对进制取余后存入buf数组
            while(i <= -radix) {
                buf[charPos--] = (byte)digits[-(i % radix)];
                i /= radix;
            }
            //最后还要进行一次转换
            buf[charPos] = (byte)digits[-i];
            //如果i小于0,在结果的最前面加上负号
            if (negative) {**
                --charPos;
                buf[charPos] = 45;
            }
            //返回buf数组的有效位数的字符串
            return StringLatin1.newString(buf, charPos, 33 - charPos);
        }
    }
  • 其中,上面的digits是Integer类中的常值数组。
static final char[] digits = new char[]{'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'};

官方API说明:

  • public static String toString(int i, int radix)

  • 参数:

    • i - 要转换成字符串的整数。
    • radix - 用于字符串表示形式的基数。
  • 返回值:

    • String类型,使用指定基数的参数的字符串表示形式。
  • 返回用第二个参数指定基数表示的第一个参数的字符串表示形式。

  • 如果基数小于 Character.MIN_RADIX 或者大于 Character.MAX_RADIX,则改用基数 10。

  • 如果第一个参数为负,则结果中的第一个元素为 ASCII 的减号 '-' ('\u002D')。如果第一个参数为非负,则没有符号字符出现在结果中。


逐行阅读,欣赏JDK作者的编码风格!

  • 第一个判断,判断基数的有效性,如果超过指定的基数范围,则返回原数字。

    • 数据有效性的判断
  • 然后,如果基数为10,直接调用将该数字转换为字符串的方法。

    • 特殊情况的考虑
  • 紧接着,就是正文了,若是其它基数,就开始进行转换。

  • 定义一个长度为33的buf字节数组。

    • 为什么是字节数组?

      • 因为字节数组的大小是-128到+127,处理这些单个的数字足矣。
      • 合适数据类型的选取
    • 为什么长度是33?

      • 因为一个int类型的数据,转换成二进制最多也才32位,再加上考虑符号的问题,设成33已经足够满足所有有效的转换了。
      • 对数组大小的合理估计
  • 定义了一个boolean类型的negtive,用于判断i是否小于0。

    • 符号处理一
  • 定义了一个charPos,用于控制数组下标。(其实用byte也可以)

  • 如果i是正数,先将正数变成负数,方便后续统一的进行进制转换。

    • 符号处理二
  • 接下来就是进制转换的核心部分了:

    • 循环条件是:i<=-radix,这里的i始终是负数,radix始终是正数

    • buf[charPos--] = (byte)digits[-(i % radix)];

      • 巧妙的利用一个静态数组digits,使得任何进制的转换统一化】。
      • 倒序存储,模仿进制转换栈原理】。
    • i /= radix;,进制转换的原理。

  • 退出循环后,i的最后部分也需要加入byte数组。

  • 如果i小于0,在最前面加上负号。(负号的ASCII码为45)

    • 符号处理三
  • 最后将buf数组有效转换成字符串输出。


代码看完了,怎么样?是不是发现JDK作者的这种编码风格非常的好呀,非常严谨,对细节处理的非常到位,难怪说JDK源码是java程序员的字典,确实,里面有很多东西值得我们去思考!

  • 以后面试官再让你手写进制转换,直接默写源码!

猜你喜欢

转载自blog.csdn.net/ATFWUS/article/details/106317756