Java基础之String 与 int两者之间如何相互转换?

在某一次面试中,面试官问了我一个问题,他说,String str = “1234”;如何在不使用 JDK自带方法的情况下,转换成 int i = “123”。当时想法思路都有了,但是没写出来......

本篇将讲述一下 String 与 int 两者之间是如何相互转换的,推荐用时:2小时。

 

String 转 int

其实这种东西JDK早就给你想到了,咱们看一下int的封装数据类型是怎么解决这个问题的;

Integer.parseInt(s)

    private static void stringToIntOne() {
        String s = "1234";
        int i = Integer.parseInt(s);

        System.out.println(i);
    }

输出结果:

源码分析

将字符串参数解析为带符号的十进制整数,前提是字符串的内容为整数,且 可以存在 +号或者-号。

ASCII {@code '-'} ({@code '\u005Cu002D'})
ASCII {@code '+'} ({@code '\u005Cu002B'}) 

Integer.parseInt();方法底层其实调用的是

parseInt(String s, int radix)
            throws NumberFormatException{}

如果出现以下任何一种情况,则抛出类型{@code NumberFormatException}的异常:

  1. 第一个参数,是{@code null}或者是这个字符串长度为零‘
  2. 第二个参数,也就是进制基数小于{@link java.lang.Character#MIN_RADIX}或大于{@link java.lang.Character#MAX_RADIX},最小值为2,最大值为36;
  3. 字符串的任何字符都不是指定的数字,但第一个字符可能是减号{@code' - '}({@code'\ u005Cu002D'})或加号{@code'+'}({@code'\ u005Cu002B'})前提是字符串长度超过1;
  4. 字符串内容不是int类型的内容;

看一下源码主干

 1.8的和1.7的源代码一样,这里就不冗余贴出来了,对应jdk1.8源代码并做了相应的注解源码如下所示,帮助大家一起更加深入的理解:

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.
     */
    // 下面三个判断好理解,其中表示进制的 radix 要在(2~36)范围内  
    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");
    }

    /**
    * 表示结果, 在下面的计算中会一直是个负数
    * 假如说 我们的字符串是一个正数  "7",那么在返回这个值之前result保存的是 -7
    * 这个可能是为了保持正数和负数在下面计算的一致性
    */
    int result = 0;
    boolean negative = false;
    int i = 0, len = s.length();

    /**
    * limit 默认初始化为 最大正整数的 负数 ,假如字符串表示的是正数
    * 那么result(在返回之前一直是负数形式)就必须和这个最大正数的负数来比较,判断是否溢出
    */
    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;
        /**
        * len为输入字符串的长度,i为循环len自增变量
        * result初始值为0,multmin初始值为最大负整数/进制数
        */
        while (i < len) {
            // Accumulating negatively avoids surprises near MAX_VALUE
            //根据Character类获取当前对应字符对应进制的数字
            digit = Character.digit(s.charAt(i++),radix);
            if (digit < 0) {
                throw NumberFormatException.forInputString(s);
            }

            /**
            * 这里就是上面说的判断溢出,由于result统一用负值来计算,所以用了 小于 号
            */
            if (result < multmin) {
                throw NumberFormatException.forInputString(s);
            }
            result *= radix;
            if (result < limit + digit) {
                throw NumberFormatException.forInputString(s);
            }
            result -= digit;
            /**
            * 再来个假设:一开始输入一个数字字符串为123,那么对应的radix=10(因为是10进制的),digit = 123 / 10 计算得到的
            * 第一次result *= radix --> result = 0 ;  result -= digit --> result = -1
            * 第二次result *= radix --> result = -10; result -= digit --> result = -12
            * 第三次result *= radix --> result = -12; result -= digit --> result = -123
            * 此时,negative = false,则返回 -result,即最终结果为:123
            */
        }
    } else {
        throw NumberFormatException.forInputString(s);
    }
    return negative ? result : -result;
}

分析步骤:

前置条件:定义int返回值,是否为负数bool,循环遍历初始值,字符串长度值,int的最小值(-2^31-1)

  1. 判断是否为null,判断是否低于2进制,大于36进制,判断长度是否大于0,满足以上判断都抛异常;
  2. 将String 转换成 char数组,取第一个字符与字符串“0”比较,判断是否是“+”,“-”;
  3. 如果是负数,将定义负数的bool给于true操作,将初始值给于int最小值;
  4. 判断长度为1且不是+-,抛出异常;
  5. 为防止溢出,定义一个最小值除以进制的数;
  6. while 循环,分别通过Character方法,取出对应的字符值;
  7. 比较返回的结果是否小于定义防止溢出的值,统一用负数来比较,所以溢出值默认用-;
  8. 返回结果在赋值成除进制之前的值,然后在减去上一次循环获取到的值;

比如:

  1. 开始输入一个数字字符串为123,那么对应的radix=10(因为是10进制的),digit = 123 / 10 计算得到的
  2. 第一次result *= radix --> result = 0 ;  result -= digit --> result = -1
  3. 第二次result *= radix --> result = -10; result -= digit --> result = -12
  4.  第三次result *= radix --> result = -12; result -= digit --> result = -123
  5. 此时,negative = false,则返回 -result,即最终结果为:123

 从以上源码可以看出,作者在计算整型数字的时候是采用取反的操作,即正数是通过负数进行计算,返回再取反操作。我猜想这样是为了在计算正负数的时候采取相同的策略,不需要为正数写一套方案,负数写一套方案,可以避免重复代码的嫌疑。

JDK中的举例

     * <p>Examples:
     * <blockquote><pre>
     * parseInt("0", 10) returns 0
     * parseInt("473", 10) returns 473
     * parseInt("+42", 10) returns 42
     * parseInt("-0", 10) returns 0
     * parseInt("-FF", 16) returns -255
     * parseInt("1100110", 2) returns 102
     * parseInt("2147483647", 10) returns 2147483647
     * parseInt("-2147483648", 10) returns -2147483648
     * parseInt("2147483648", 10) throws a NumberFormatException
     * parseInt("99", 8) throws a NumberFormatException
     * parseInt("Kona", 10) throws a NumberFormatException
     * parseInt("Kona", 27) returns 411787
     * </pre></blockquote>

Integer.valueOf(s)

    private static void stringToIntTwo() {
        String s = "5678";
        int i = Integer.valueOf(s);

        System.out.println(i);
    }

输出结果:

源码分析

同:Integer.parseInt(s),不做过多叙述。

关于 Integer.valueOf():

Integer.parseInt(s)与Integer.parseInt(s)的区别

Integer.parseInt(s)返回值为Int型,而Integer.valueOf(s)返回值为Integer,区别在于后者能够使用Integer的一些方法。

在不适用Integer自带方法情况下,自行实现

这个是面试题,划重点:

    private static void stringToIntThree() {
        String s = "18188";
        // 把字符串转换成数组
        String[] split = s.split("");
        // 定义输出值 num 初始值为0
        double num = 0;
        // 获取数组 长度,用于计算
        int arr = split.length;
        for (int i = 0; i < split.length; i++) {
            int c = Character.digit(s.charAt(i),10);
            num += c*Math.pow(10,arr-i-1);
        }
        System.out.println((int)num);
    }

输出结果

int 转 String

其实万事万物,皆可 toString();

Integer.toString(i)

    private static void intToStringOne() {
        int i = 10000;
        String sss= Integer.toString(i);

        System.out.println(sss);
    }

输出结果:

 

其实万事万物,皆可 valueOf();

String.valueOf(i)

    private static void intToStringTwo() {
        int i = 10010;
        String ss = String.valueOf(i);

        System.out.println(ss);
    }

输出结果:

源码分析

返回{@code int}参数的字符串表示形式。

toString():

最终是 new String();

“”+

    private static void intToStringThree() {
        int i = 8888;
        String str=i+"";

        System.out.println(str);
    }

输出结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值