java string和int转换,java中int和string转换
00-1010int到string vs. string到int:string到int的效率比较,int到string的两种方法一般用三种方法来分析string到Int的问题。一波1,输入字符串是空对象还是空字符串的处理2,符号位的处理3,错别字的处理4,整形数据超出范围的处理5,int数据范围的讨论。总结原码,反码,补码。
目录
00-1010整数。PARSEINT(字符串)整数。(字符串)的值。INTVALUE()第二种方法可以看看源代码,实现第一种方法。
评论大概就是这个意思。
/* * *返回由包含整数*的对象指定的{@ String String}的值。该语句*被解释为一个带符号的十进制整数*,就像该参数被提供给{@link的* #parseInt(java.lang.String)}方法一样。结果是一个integer对象,表示由字符串指定的整数值*。*换句话说,该方法返回一个等于下列值的{@code Integer} *对象:* * block quote * { @ code new Integer(Integer . parse int(s))} */block quote * * @ param是要解析的字符串。* @返回一个{integer}对象,其中保存的值*由字符串参数表示。* @ Exception NumberFormatException如果字符串不能被解析为整数。parseInt()方法在valueOf()中实现。与时间相比,第二个比第一个快得多。
integer . parse int(str): 21 integer . value of(str)。intValue() : 14
00-1010第一个:number 第二个:string.valueOf()第三个:toString()先说第一个,简单粗暴。第二种方法:底层仍然使用。toString()方法,第三个方法是toString()上的代码。
int num=888888//(1)num long start=system . current time millis();//获取运行时开始时的系统时间(int I=0;i100000I){ String str=num“”;} long end=system . current time millis();//获取结束运行时系统时间system . out . println( num : (end-start));//(2)string . value of(num)start=system . currenttimemillis();for(int I=0;i100000I){ String str=String . value of(num);} end=system . current time millis();system . out . println( string . value of(num): (end-start));//(3)integer . tostring(num)start=system . current time millis();for(int I=0;i100000I){ String str=integer . tostring(num);} end=system . current time millis();system . out . println( integer . tostring(num): (end-start));结果是。
编号 : 82字符串
.valueOf(num) : 32Integer.toString(num) : 9
经过多次的反复测试,toString()是最快的,num+""是最慢的,在使用String.valueOf()中源码是这样的。
public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString();}
也就是说在使用的时候,不用去判断所传的对象是否为null,但是尤其注意,如果传的为空,返回来的是一个为null的字符串而不是null值,这个地方需要谨记。
string转int问题分析
相信很多同学在面试时都遇到过这样一个问题,要求封装一个函数,将String类型转换为int类型。这个看似简单的问题其实隐藏着很多细节,要想真正封装好这个函数并不容易。面试官要考察的其实并不是算法本身的难度,这个问题的算法其实没有什么难度可言,主要要考察的是程序员写代码的仔细程度,考虑问题是否全面,也就是说,我们要尽可能的让代码具有鲁棒性。下面我们一步步的分析这个问题中隐藏的细节。
分析一波
首先我们不考虑任何的异常处理,假设函数的调用者传入的数据都是正确的,很容易就可以写出下面的代码:
public int strToInt(String str) { int number = 0; for (int i=0; i<str.length(); i++) { number *= 10; number += (str.charAt(i) - 0); } return number; }
上面的代码将遍历字符串的每一位字符,并将其转换为对应的整数,然后将其一一融入到整形数据number中。
如果你给面试官提交的是这样一份代码,结果肯定不会满意。因为你没有考虑到程序的鲁棒性,我们封装的函数相当于API接口,是提供给所有开发者调用的,难免其他开发者不会传入一些奇怪的参数,而这段代码对异常参数没有做任何处理,一旦传入异常参数,程序将直接崩溃。下面我们一步步来完善这个函数,提高其鲁棒性。
1、针对传入的字符串为空对象或者字符串为空的字符串
public int strToInt(String str) throws NumberFormatException{ if (str == null str.contentEquals("")) { // 如果传入的字符串为空对象或者传入的字符串为空字符串,则抛出异常 throw new NumberFormatException("null or empty string"); // 这里直接利用java封装好的异常类,当然我们也可以自己封装异常类,面试官要考察的不是对异常类的封装,而是你要知道要处理异常情况 } int number = 0; for (int i=0; i<str.length(); i++) { number *= 10; number += (str.charAt(i) - 0); } return number; }
首先我们字符串是否为空或者是否为空的字符串,如果是,则直接抛出异常,这里我们使用的是Java封装好的异常类NumberFormatException,当然我们也可以自己封装异常类,面试官要考察的不是对异常类的封装,而是你要知道要处理异常情况。
2、针对符号位的处理
这个我们最好提前问一下面试官,有没有可能传入的是负数,当为正数时,是否允许带符号位,如果是的话,我们就要针对符号位进行处理,负数的第一个字符是-,我们只要判断第一个字符是否为-就可以知道传入的是否为负数了,如果正数允许带符号位,那边第一个字符有可能是+,我们也要做对应的处理:
public int strToInt(String str) throws NumberFormatException{ if (str == null str.contentEquals("")) { // 如果传入的字符串为空对象或者传入的字符串为空字符串,则抛出异常 throw new NumberFormatException("null or empty string"); // 这里直接利用java封装好的异常类,当然我们也可以自己封装异常类,面试官要考察的不是对异常类的封装,而是你要知道要处理异常情况 } boolean negative = false; // negative为true表示是负数,反之为正数 int pos = 0; if (str.charAt(0) == -) { // 如果为负数 negative = true; pos++; // 调过第一位符号位 } else if (str.charAt(0) == +) { pos++; // 调过第一位符号位 } int number = 0; while (pos < str.length()) { number *= 10; number += (str.charAt(pos) - 0); pos++; } return negative ? -number : number; // 如果为负数则返回对应的负数 }
3、针对错误字符的处理
函数的调用者可能会传入一下乱七八糟的字符串,比如abc23123,针对这种情况我们也要做对应的处理,应该给调用者抛出一个异常,告知其传入的字符串是非法字符串:
public int strToInt(String str) throws NumberFormatException{ if (str == null str.contentEquals("")) { // 如果传入的字符串为空对象或者传入的字符串为空字符串,则抛出异常 throw new NumberFormatException("null or empty string"); // 这里直接利用java封装好的异常类,当然我们也可以自己封装异常类,面试官要考察的不是对异常类的封装,而是你要知道要处理异常情况 } boolean negative = false; // negative为true表示是负数,反之为正数 int pos = 0; if (str.charAt(0) == -) { // 如果为负数 negative = true; pos++; // 调过第一位符号位 } else if (str.charAt(0) == +) { pos++; // 调过第一位符号位 } int number = 0; while (pos < str.length()) { if (str.charAt(pos) >= 0 && str.charAt(pos) <= 9) { // 只有字符在0到9的范围内,才算正确的字符 number *= 10; number += (str.charAt(pos) - 0); pos++; } else { throw new NumberFormatException("invalid string"); // 当字符是其他字符时,抛出异常告知调用者传入的字符串错误 } } return negative ? -number : number; // 如果为负数则返回对应的负数 }
4、针对整形数据超出范围的处理
调用者传入的字符串可能是一个很长的字符串,转换为整数可能超出了整数的存储范围,比如12345678674324334,在这种情况下,我们要抛出一个异常告知调用者传入的字符串超出了整形的范围:
public int strToInt(String str) throws NumberFormatException{ if (str == null str.contentEquals("")) { // 如果传入的字符串为空对象或者传入的字符串为空字符串,则抛出异常 throw new NumberFormatException("null or empty string"); // 这里直接利用java封装好的异常类,当然我们也可以自己封装异常类,面试官要考察的不是对异常类的封装,而是你要知道要处理异常情况 } boolean negative = false; // negative为true表示是负数,反之为正数 int pos = 0; if (str.charAt(0) == -) { // 如果为负数 negative = true; pos++; // 调过第一位符号位 } else if (str.charAt(0) == +) { pos++; // 调过第一位符号位 } int limit = negative ? (-Integer.MIN_VALUE) : Integer.MAX_VALUE; int mult = limit / 10; // 记录最大数/10,让number和这个数比较,如果大于它,则number * 10肯定也就大于最大数 int number = 0; while (pos < str.length()) { if (str.charAt(pos) >= 0 && str.charAt(pos) <= 9) { // 只有字符在0到9的范围内,才算正确的字符 if (number > mult) {// 让number和mult比较,如果大于它,则number * 10肯定也就大于最大数 throw new NumberFormatException("input string beyond int size"); } number *= 10; int digit = str.charAt(pos) - 0; if (number > limit - digit) { // 这里不能用number + digit > limit来判断,因为number + digit可能超出整数的存储范围,相加后的数可能是一个负数,但是limit - digit肯定不会超出 throw new NumberFormatException("input string beyond int size"); } else { number += digit; } pos++; } else { throw new NumberFormatException("invalid string"); // 当字符是其他字符时,抛出异常告知调用者传入的字符串错误 } } return negative ? -number : number; // 如果为负数则返回对应的负数 }
上面的代码中,我们判断number是否会超出最大整数时首先是先让其(最大整数/10)的值比较,而不是让其乘以10与最大整数比较,这是因为number * 10如果超出了整数范围,则会造成数据溢出,其得到的值可能是一个负数,而(最大整数/10)的值是不会数据溢出的,这也是一个小细节。可能你以为这样这个函数就完美了,但是现在我要告诉你,上面的写法是错误的。
为什么呢?这要从整数的范围说起,整数的取值范围是(-2^31)至(2^31 - 1),从绝对值的角度看,最小负数相比于最大正数大1。所以上面代码中(-Integer.MIN_VALUE)会超出整形的范围,造成数据溢出,也就是说上面的代码对负数最小范围的限制的处理是错误的。那么怎么解决这个问题呢?
我们换个角度思考,最小负数的绝对值比最大正数的绝对值大1,那(-Integer.MAX_VALUE)的值肯定不会超出整数的范围,我们现在的程序是以正数的方式处理,如果反过来已负数的方式处理,问题不就解决了吗?修改代码如下:
public int strToInt(String str) throws NumberFormatException{ if (str == null str.contentEquals("")) { // 如果传入的字符串为空对象或者传入的字符串为空字符串,则抛出异常 throw new NumberFormatException("null or empty string"); // 这里直接利用java封装好的异常类,当然我们也可以自己封装异常类,面试官要考察的不是对异常类的封装,而是你要知道要处理异常情况 } boolean negative = false; // negative为true表示是负数,反之为正数 int pos = 0; if (str.charAt(0) == -) { // 如果为负数 negative = true; pos++; // 调过第一位符号位 } else if (str.charAt(0) == +) { pos++; // 调过第一位符号位 } int limit = negative ? Integer.MIN_VALUE : (-Integer.MAX_VALUE); int mult = limit / 10; int number = 0; while (pos < str.length()) { if (str.charAt(pos) >= 0 && str.charAt(pos) <= 9) { // 只有字符在0到9的范围内,才算正确的字符 if (number < mult) { throw new NumberFormatException("input string beyond int size"); } number *= 10; int digit = str.charAt(pos) - 0; if (number < limit + digit) { throw new NumberFormatException("input string beyond int size"); } else { number -= digit; } pos++; } else { throw new NumberFormatException("invalid string"); // 当字符是其他字符时,抛出异常告知调用者传入的字符串错误 } } return negative ? number : -number; }
OK,现在我们把能够想到的异常情况处理了。再来考虑一个问题,为什么整形数据的范围是(-2^31)至(2^31 - 1),最小负数的绝对值比最大正数的绝对值要大1呢?
5、int数据范围的讨论
我们知道,一个int类型占四个字节,也就是32位,其中第一位是符号位,符号位为0表示正数,为1表示负数,其余31位表示数值。正常来说int类型的数据范围应该是(-2^31-1)到(2^31-1),为什么负数会多一位呢?
我们首先看一下Java代码中对Integer.MAX_VALUE和Integer.MIN_VALUE的定义:
/** * A constant holding the minimum value an {@code int} can * have, -2<sup>31</sup>. */ public static final int MIN_VALUE = 0x80000000; /** * A constant holding the maximum value an {@code int} can * have, 2<sup>31</sup>-1. */ public static final int MAX_VALUE = 0x7fffffff;
原码、反码、补码
我们知道,在计算机中,数据都是以二进制的形式存储的,比如,数字10,其二进制形式就是1010。
一个字节有8位,每位可以存储一个01字符,byte类型占1个字节,也就是8位,其中,最高位是符号位,用来表示数值是正数还是负数,符号位为0表示正数,符号位为1表示负数。我们先来看一下原码、反码、补码的定义:
原码:符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值。反码:正数的反码是其本身;负数的反码是在其原码的基础上, 符号位不变,其余各个位取反。补码:补码的表示方法是:正数的补码就是其本身;负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1。 (即在反码的基础上+1)正数的原码、反码、补码都是其本身;负数的反码是在其原码的基础上,符号位不变,其余个位取反,负数的补码是其反码的基础上+1。
举例说明(下面都以byte类型进行举例):
数据原码反码补码10000010100000101000001010-10100010101111010111110110计算机中,数据都是以补码的形式存储的。为什么要以补码的形式存储呢?有两个原因:
1、如果数值以补码的形式保存,对一个数进行求补运算,可以得到其相反值
求补运算:将一个数(包括正数和负数)所有二进制位(包括符号位和数值位)取反,然后在最低位加上1。
为什么对一个数进行求补运算,可以得到其相反值呢?我们先来分析一下求补运算的定义,现将所有的二进制取反,然后+1,首先一个数和它所有位取反得到的数相加,其结果肯定是11111111,这是因为它们每一位都不一样,然后将结果+1,即11111111 + 1,结果是1 00000000,最高位的1已经溢出,换种方式说,如果以f(n)表示对n进行求补运算,那么对于任意的范围内的数,可以得到:
n + f(n) = 1 00000000
即
f(n) = 1 00000000 - n
而对于一个正数来说,对其进行求补运算其实得到的就是它的相反数的补码(负数的补码符号位保持不变,其他为全部取反再+1,因为正数和负数的符号位本来就不一样,所以对一个正数进行求补其实得到的就是它的相反数的补码)。
那么对于一个负数来说呢?对其进行求补运算是否能够得到其对应的正数的补码呢?
假设n>0,根据上面可知:
f(n) = 1 00000000 - n
对f(n)进行求补运算,有:
f(f(n)) = f(1 00000000 - n) = 1 00000000 - (1 00000000 - n) = n
其中,1 00000000 - n表示n对应负数的补码,对其进行求补运算得到的就是n,正数的补码就是其原码。
由上可知:如果数值以补码的形式保存,对一个数进行求补运算,可以得到其相反值,即:f(n) = -n
2、方便减法运算
如果数值以补码的方式存储,可以将减法变为加法,省去了减法器,通过上面的推导,如果数据以补码的方式存储,以f(n)表示对n进行求补运算,可以得到:
f(n) = -n
那么现在我们需要计算m - n,应该要怎么计算呢?如果以补码的方式存储,那么就有:
m - n = m + (-n) = m + f(n)
也就是说,减去一个数只需要加上对其进行求补运算后得到
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。