java中整数和字符串间的转换方法

java中整数和字符串间的转换方法

    如果让您亲自动手来来写一个Integer中的toString()方法和parseInt()方法,您会怎么写?
    
    请您先动手写toString()方法。
    
    我对于toString()的思路:
    
    1.首先需要得到这个Integer数值的位数,所以肯定有一个getIntegerSize()的private方法
    
    2.然后要把这个Integer数值转化为一个字符数组,所以也要有一个getChars()的private方法
    
    3.最后只要把这个字符数组转化为字符串返回即可
    
    在编写完我们的代码,再确定对于现在自己的实力,已经没有再做优化的可能之后,再来看Integer中的toString()来领教一下高手的代码是怎么写的。
    
    下面是这个过程中最重要的一步:将数值转成字符数组;
    
    其中用使用来三个表(DigitOnes、DigitTens、digits)作为表驱动法(在代码大全上看到过,但还没用过:P)的快速索引来加快代码的执行效率。
    
    [java] view plaincopyprint?
    
    01./**
    
    02. * @param i 被转十进制数
    
    03. * @param index 这个十进制数的总位数
    
    04. * @param buf 用来存储转化后的结果
    
    05. */
    
    06.static void getChars(int i, int index, char[] buf) {
    
    07. int q, r;
    
    08. int charPos = index;
    
    09. char sign = 0;
    
    10.
    
    11. if (i < 0) {
    
    12.     sign = '-';
    
    13.     i = -i;
    
    14. }
    
    15.
    
    16. // Generate two digits per iteration
    
    17. while ( i >= 65536 ) {
    
    18.     q = i / 100;
    
    19.     r = i - ( ( q 《 6 ) + ( q 《 5 ) + ( q 《 2 ) ); // 高效实现 r = i - ( q * 100 );
    
    20.     i = q;
    
    21.     buf [ --charPos ] = DigitOnes[ r ];
    
    22.     buf [ --charPos ] = DigitTens[ r ];
    
    23. }
    
    24.
    
    25. // Fall thru to fast mode for smaller numbers
    
    26. // assert( i <= 65536, i );
    
    27. for (;;) {
    
    28.     q = ( i * 52429 ) >>> (16+3 ); //实现 q = i / 10(其中使用整数乘法后再移位来代替浮点数的乘法(q * 0.1),但对于现在的CPU来说不        //知是否还是整数乘法较快?)

    29.     r = i - ( ( q 《 3 ) + ( q 《 1 ) );  //高效实现 r = i - ( q * 10 ) …
    
    30.     buf [ --charPos ] = digits [ r ];
    
    31.     i = q;
    
    32.     if ( i == 0 ) break;
    
    33. }
    
    34. if ( sign != 0 ) {
    
    35.     buf [ --charPos ] = sign;
    
    36. }
    
    37.}
    
    /**
    
    * @param i 被转十进制数
    
    * @param index 这个十进制数的总位数
    
    * @param buf 用来存储转化后的结果
    
    */
    
    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;
    
    r = i - ( ( q 《 6 ) + ( q 《 5 ) + ( q 《 2 ) ); // 高效实现 r = i - ( q * 100 );
    
    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 ); //实现 q = i / 10(其中使用整数乘法后再移位来代替浮点数的乘法(q * 0.1),但对于现在的CPU来说不        //知是否还是整数乘法较快?)成都java培训
    
    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;
    
    }
    
    }
    
    在给出DigitOnes、DigitTens、digits的三个表之后,我相信看懂这段代码应该是比较简单的事情了(可以写一个具体的数字,比如666666带进去试一下)。但是采用上面的代码来实现仍然存在一个缺陷,就是Integer.MIN_VALUE是不能采用这种方式来转换的。以为当其转化为整数后将要超出Integer的最大范围,所以在toString()方法中还要加入预防措施。

    [java] view plaincopyprint?
    
    01./**
    
    02. * All possible chars for representing a number as a String
    
    03. */
    
    04. final static char[] digits = {
    
    05.  '0' , '1' , '2' , '3' , '4' , '5' ,
    
    06.  '6' , '7' , '8' , '9' , 'a' , 'b' ,
    
    07.  'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
    
    08.  'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
    
    09.  'o' , 'p' , 'q' , 'r' , 's' , 't' ,
    
    10.  'u' , 'v' , 'w' , 'x' , 'y' , 'z'
    
    11. };
    
    12.
    
    13. /**
    
    14.  * 传入一个二位十进制数,返回其十位上的数值
    
    15.  */
    
    16. final static char [] DigitTens = {
    
    17.  '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
    
    18.  '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
    
    19.  '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
    
    20.  '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
    
    21.  '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
    
    22.  '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
    
    23.  '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
    
    24.  '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
    
    25.  '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
    
    26.  '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
    
    27. } ;
    
    28.
    
    29. /**
    
    30.  * 传入一个二位十进制数,返回其个位上的数值
    
    31.  */
    
    32. final static char [] DigitOnes = {
    
    33.  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    34.  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    35.  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    36.  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    37.  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    38.  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    39.  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    40.  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    41.  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    42.  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    43. } ;
    
    /**
    
    * All possible chars for representing a number as a String
    
    */
    
    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'
    
    };
    
    /**
    
    * 传入一个二位十进制数,返回其十位上的数值
    
    */
    
    final static char [] DigitTens = {
    
    '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
    
    '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
    
    '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
    
    '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
    
    '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
    
    '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
    
    '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
    
    '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
    
    '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
    
    '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
    
    } ;
    
    /**
    
    * 传入一个二位十进制数,返回其个位上的数值

    */
    
    final static char [] DigitOnes = {
    
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    
    } ;
    
    虽然API的实现耗费了不少空间,但是其效率要比我写的要快多了(- -!!)。如果大家不明白上面的位移操作符可以看:Java中的位移运算符
    
    对于得到一个整数数值的位数,我采用了的是不断取余操作(不知道多少兄弟和我想到一块儿去了,^ ^.但是取余操作效率相比之下要慢上不少)。那么API是如何快速得到一个整数数值的位数的呢?其中又采用了表驱动法来取代if-else:成都java培训
    
    [java] view plaincopyprint?
    
    01.final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
    
    02.                                      99999999, 999999999, Integer.MAX_VALUE };
    
    03.
    
    04. // Requires positive x
    
    05. static int stringSize( int x ) {
    
    06.  for ( int i=0; ; i++ )
    
    07.      if ( x <= sizeTable[i] )
    
    08.   return i+1;
    
    09. }
    
    10.
    
    11. 好了,现在是时候来看一下toString()方法了
    
    12. public static String toString( int i ) {
    
    13.  if ( i == Integer.MIN_VALUE )
    
    14.   return "-2147483648";
    
    15.  int size = ( i < 0 ) ? stringSize( -i ) + 1 : stringSize( i );
    
    16.  char[] buf = new char[ size ];
    
    17.  getChars( i, size, buf );
    
    18.  return new String( 0, size, buf );
    
    19. }
    
    final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
    
    99999999, 999999999, Integer.MAX_VALUE };
    
    // Requires positive x
    
    static int stringSize( int x ) {
    
    for ( int i=0; ; i++ )
    
    if ( x <= sizeTable[i] )
    
    return i+1;
    
    }
    
    好了,现在是时候来看一下toString()方法了
    
    public static String toString( int i ) {
    
    if ( i == Integer.MIN_VALUE )
    
    return "-2147483648";
    
    int size = ( i < 0 ) ? stringSize( -i ) + 1 : stringSize( i );
    
    char[] buf = new char[ size ];
    
    getChars( i, size, buf );
    
    return new String( 0, size, buf );
    
    }
    
    这样toString()方法就实现了。
    
    接下来请大家动手写parseInt()的方法:
    
    下面是我的思路
    
    1.首先自然也是要取得这个字符串的长度,不过这里很简单,直接使用String的length()方法就可以了
    
    2.取出字符串中的第一个字符,判断是否是正负符号。如果不是的话则判断是否符合整数的条件,由于
    
    这里取出的整数和ASCII码相差48,取出的数需要减去48之后,再加入到result中,然后将result * 10
    
    3.不断循环,知道result的长度达到字符串的长度,或者result的值超越的整数的最大范围,则退出程序。
    
    以下是API中的源码(省略其中转为其他进制数的代码):
    
    [java] view plaincopyprint?
    
    01.public static int parseInt( String s )
    
    02.           throws NumberFormatException {
    
    03. if ( s == null ) {
    
    04.     throw new NumberFormatException( "null" );
    
    05. }
    
    06.
    
    07. int result = 0;
    
    08. boolean negative = false;
    
    09. int i = 0;
    
    10. int len = s.length();
    
    11. int limit = -Integer.MAX_VALUE;
    
    12. int multmin; //用来放置整数的最大范围
    
    13. int digit;
    
    14. int radix = 10;
    
    15.
    
    16. if ( len > 0 ) {
    
    17.     char firstChar = s.charAt( 0 );
    
    18.     if ( firstChar < '0' ) { // Possible leading "+" or "-"
    
    19.         if ( firstChar == '-' ) {
    
    20.             negative = true;
    
    21.             limit = Integer.MIN_VALUE;
    
    22.         } else if ( firstChar != '+' )
    
    23.             throw NumberFormatException.forInputString( s );
    
    24.
    
    25.         if ( len == 1 ) // Cannot have lone "+" or "-"
    
    26.             throw NumberFormatException.forInputString( s );
    
    27.         i++;
    
    28.     }
    
    29.     multmin = limit / radix;
    
    30.     while ( i < len ) {
    
    31.         // Accumulating negatively avoids surprises near MAX_VALUE
    32.         digit = Character.digit( s.charAt( i++ ), radix ); //这一步应该是符合我的思路的第二条,我想如果应用上面的digits表应该也可以轻易做到
    
    33.         if ( digit < 0 ) {
    
    34.             throw NumberFormatException.forInputString( s );
    
    35.         }
    
    36.         if ( result < multmin ) {
    
    37.             throw NumberFormatException.forInputString( s );
    
    38.         }
    
    39.         result *= radix;
    
    40.         if ( result < limit + digit ) {
    
    41.             throw NumberFormatException.forInputString( s );
    
    42.         }
    
    43.         result -= digit;
    
    44.     }
    
    45. } else {
    
    46.     throw NumberFormatException.forInputString( s );
    
    47. }
    
    48. return negative ? result : -result;
    
    49.}

posted on 2012-12-03 10:39  YangJin  阅读(964)  评论(0编辑  收藏  举报