Java进制转换(源码分析)

进制转换在平时的算法练习题或者项目中都会遇到,下面我们来看一下使用java如何进行进制互相转换。

1. 使用内置函数进行进制转换

在java函数中,Integer类中已经有相应函数可以进行十进制 与 二进制,八进制和十六进制的转换。

十进制转换其他进制

  //十进制转成二进制 
  Integer.toBinaryString(int i) 
  //十进制转成八进制 
  Integer.toOctalString(int i) 
  //十进制转成十六进制: 
  Integer.toHexString(int i)

其他进制转换十进制
  

   //二进制转十进制 
  Integer.valueOf("10111",2).toString()
  //八进制转成十进制 
  Integer.valueOf("188",8).toString() 
  //十六进制转成十进制 
  Integer.valueOf("ABC",16).toString() 

  
  使用java提供的函数进行进制转换只能进行二进制,八进制,十进制和十六进制间的转换,这可能还不能满足我们的需求,那么如何实现任意进制的转换呢。

2. 模运算

可以使用离散数学的模运算来进行进制的转换。具体的计算过程这里就不赘述了,下面是相应代码。

十进制到任意进制的转换:

    public static String Dec2Any(int n,int k){
        Stack s = new Stack();
        String result = "";
        int i = 0;
        while(n != 0){
            s.push(n % k);
            n = n / k;
            i ++;
        }
        while(i > 0){
            result = result + s.pop();
            i--;
        }
        return result;  
    }

上面的代码需要注意一个问题,就是把十进制的数转为超过十进制的数字时,需要用相应的多进制表示符号替换。

也可以直接进行运算来获取任意进制到十进制数的转换,代码如下

    public static int Any2Dec(String num,int k){
        int f=1;
        int result = 0;
        for (int i=num.length()-1;i>=0;i--)
           {
                if (num.charAt(i)=='A'||num.charAt(i)=='B'||num.charAt(i)=='C'||num.charAt(i)=='D'||num.charAt(i)=='E'||num.charAt(i)=='F')
                {
                    result = result + f * (num.charAt(i)-'A'+10);
                }
                else
                {         
                    result = result + f * (num.charAt(i)-'0');
                }
                f = f * k;
           }
        return result;
    }

3. 位运算

以前进行进制转换,我也只会想到使用模运算,但是后来通过查看java的Integer中进制转换的源码,发现java内部是使用位运算进行进制转换的。

我们首先看十进制到其他进制的转换,相应函数的源码如下

   public static String toBinaryString(int i) {
        return toUnsignedString(i, 1);
    }
   public static String toOctalString(int i) {
        return toUnsignedString(i, 3);
    }
        public static String toHexString(int i) {
        return toUnsignedString(i, 4);
    }

我们可以看到,内部是通过调用了toUnsignedString(int i)这个函数来实现进制转换的。

    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'
    };
    private static String toUnsignedString(int i, int shift) {
        char[] buf = new char[32];
        int charPos = 32;
        int radix = 1 << shift;
        int mask = radix - 1;
        do {
            buf[--charPos] = digits[i & mask];
            i >>>= shift;
        } while (i != 0);

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

因为我对位运算不是很熟悉,因此看起来还是挺有难度的,这里对函数进行一个解析,以十进制转为十六进制toUnsignedString(i, 4)为例。

int radix = 1 << shift这一行,把1左移4位,得到radix为16
int mask = radix - 1得到mask为15,其二进制形式为00001111
buf[--charPos] = digits[i & mask]中,i & mask的目的就是取i的最后4位,然后在digits表单中取到相应的十六进制字符。
i >>>= shift,这一行,抛弃刚处理过的最后4位,往右再推4位,然后进入循环,直到i为0;
所有的十六进制的字符都放在了buf里面,然后组合成一个字符串,返回。

我们可以通过改写这个函数,把十进制的数转换为任意2次方进制的数。

把其他进制转换为十进制时,内部是调用了Integer的parseInt(String s, int radix)方法。代码如下:

 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.
         */

        if (s == null) {
            throw new NumberFormatException("null");
        }

        if (radix < Character.MIN_RADIX) {
            throw new NumberFormatException("radix " + radix +
                                            " less than Character.MIN_RADIX");
        }

        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();
        int limit = -Integer.MAX_VALUE;
        int multmin;
        int digit;

        if (len > 0) {
            char firstChar = s.charAt(0);
            if (firstChar < '0') { // Possible leading "+" or "-"
                if (firstChar == '-') {
                    negative = true;
                    limit = Integer.MIN_VALUE;
                } else if (firstChar != '+')
                    throw NumberFormatException.forInputString(s);

                if (len == 1) // Cannot have lone "+" or "-"
                    throw NumberFormatException.forInputString(s);
                i++;
            }
            multmin = limit / radix;
            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 {
            throw NumberFormatException.forInputString(s);
        }
        return negative ? result : -result;
    }

核心代码是下面这部分

 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;
            }

通过学习Inreger进制转换方法的实现过程,读者可以自己对其进行改造从而实现自己需要完成的功能。毕竟使用位运算进行进制转换的效率会高一些。

你可能感兴趣的:(Java进制转换(源码分析))