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

2022-10-13 09:09:50

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

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

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

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

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

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


JDK11-Integer-toString方法

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

  • 注释为个人所写。
/**注释:ATFWUS
     * 说明:返回用第二个参数指定基数表示的第一个参数的字符串表示形式。
     * @param i 待转换的十进制数
     * @param radix 基数
     * @return String
     */publicstatic StringtoString(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){returntoString(i);}elseif(!String.COMPACT_STRINGS){returntoStringUTF16(i, radix);//采用UTF16编码的转换}else{//buf数组存储转换后的结果byte[] buf=newbyte[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类中的常值数组。
staticfinalchar[] digits=newchar[]{'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程序员的字典,确实,里面有很多东西值得我们去思考!

  • 以后面试官再让你手写进制转换,直接默写源码!
  • 作者:ATFWUS
  • 原文链接:https://atfwus.blog.csdn.net/article/details/106317756
    更新时间:2022-10-13 09:09:50