Skip to main content

moregeek program

【java】探讨 java 中 valueof 和 parseint 的区别_wx630f055ce23fc的博客-多极客编程

前言
在编程中,遇到类型转换,好像会经常用到 parseInt 和 valueOf,当然这里只拿 Integer 类型进行陈述,其他类型也是雷同的;
想必有读者也跟我一样,经常交叉使用这两个方法,但却不知道这两者到底有什么区别,接下来就来探究一番;
 
区别

Integer.parseInt(s) 的作用就是把字符串 s 解析成有符号基本类型的 int;
Integer.valueOf(s) 把字符串 s 解析成 Integer 对象类型,返回的对象可以调用 Integer 中的方法;

接下来,通过源码进行逐一解析;
 ```
parseInt
我们首先点进 parseInt() 方法中,
public static int parseInt(String s) throws NumberFormatException {
return parseInt(s, 10);
}

可以看到,这个被我们调用的 parseInt() 方法返回了一个重载方法:

public static int parseInt(String s, int radix) throws NumberFormatException {
if (s == null) {
throw new NumberFormatException("null");
} else if (radix < 2) {
throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX");
} else if (radix > 36) {
throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX");
} else {
boolean negative = false;
int i = 0;
int len = s.length();
int limit = -2147483647;
if (len <= 0) {
throw NumberFormatException.forInputString(s);
} else {
char firstChar = s.charAt(0);
if (firstChar < '0') {
if (firstChar == '-') {
negative = true;
limit = -2147483648;
} else if (firstChar != '+') {
throw NumberFormatException.forInputString(s);
}

            if (len == 1) {
throw NumberFormatException.forInputString(s);
}

++i;
}

int multmin = limit / radix;

int result;
int digit;
for(result = 0; i < len; result -= digit) {
digit = Character.digit(s.charAt(i++), radix);
if (digit < 0 || result < multmin) {
throw NumberFormatException.forInputString(s);
}

result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
}

return negative ? result : -result;
}
}

}

1、首先看到的是,该方法传入了两个参数,parseInt(String s, int radix),这个可以根据被调用时传入的参数,return parseInt(s, 10);,盲猜一下,s 就是表示要转换成数字型的字符串,而 radix 英文是基数的意思,这里应该表示进制,即这个传入的字符串是多少进制的,那到底是不是呢,我们接着往下看;
2、这里先是对字符串 s 是否为空,以及 radix 的大小进行一个判断,不符合条件则抛出 NumberFormatException 异常,也就是数字格式化异常;

if (s == null){
throw new NumberFormatException("null");
} else if (radix < 2) {
throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX");
} else if (radix > 36) {
throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX");
} else {
复制代码
3、接着往下,再一次对长度进行一个校验,
int len = s.length();
if (len <= 0) {
throw NumberFormatException.forInputString(s);
} else {
...
}

我在这里只想到了一个能让它抛出异常的条件,

Integer.parseInt("");

运行结果:

Exception in thread "main" java.lang.NumberFormatException: For input string: ""
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.base/java.lang.Integer.parseInt(Integer.java:662)
at java.base/java.lang.Integer.parseInt(Integer.java:770)

4、接下来会检测第一个字符是啥,如果是 -,则将 negative 设置成 true,表示这是个负数,并且将边界 limit 设置成最小边界;
如果不是 +,则表示该字符既不是数字,不也是性质符号,因此抛出 NumberFormatException 异常;
如果字符串 s 的长度只有1,则表明这是非数字,不符合要求,也抛出 NumberFormatException 异常;
++i 是因为如果第一位是符号的话,那么在后续的循环中追加数字则直接跳过首位;

char firstChar = s.charAt(0);
if (firstChar < '0') {
if (firstChar == '-') {
negative = true;
limit = -2147483648;
} else if (firstChar != '+') {
throw NumberFormatException.forInputString(s);
}

 if (len == 1) {
throw NumberFormatException.forInputString(s);
}

++i;

}

5、根据进制来调整边界,以防越界;

int multmin = limit / radix;

6、Character.digit() 用于将字符转为为对应进制的整数,如果该字符不是进制内的就返回-1,例如输入的字符是9,但是进制是2,那么就不符合,则会返回-1;
然后就是进行计算;

int result;
int digit;
for(result = 0; i < len; result -= digit) {
digit = Character.digit(s.charAt(i++), radix);
if (digit < 0 || result < multmin) {
throw NumberFormatException.forInputString(s);
}

result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}

}

7、最后判断是否为负数完成转换;

return negative ? result : -result;

 
valueOf
照例查看源码:

public static Integer valueOf(String s, int radix) throws NumberFormatException {
return parseInt(s, radix);
}

public static Integer valueOf(String s) throws NumberFormatException {
return parseInt(s, 10);
}

@HotSpotIntrinsicCandidate
public static Integer valueOf(int i) {
return i >= -128 && i <= Integer.IntegerCache.high ? Integer.IntegerCache.cache[i + 128] : new Integer(i);
}

可以看出 valueOf(String s, int radix) 和 valueOf(String s) 都是直接调用返回了 parseInt 方法,而 valueOf(int i) 则是一个 int 转成 Integer 的自动装箱;
接下来探究一下 IntegerCache ,可以看出这是 Integer 的成员内部类,来看源码:

private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer[] cache;
static Integer[] archivedCache;

private IntegerCache() {
}

static {
int h = 127;
String integerCacheHighPropValue = VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
int size;
if (integerCacheHighPropValue != null) {
try {
size = Integer.parseInt(integerCacheHighPropValue);
size = Math.max(size, 127);
h = Math.min(size, 2147483518);
} catch (NumberFormatException var6) {
}
}

high = h;
VM.initializeFromArchive(Integer.IntegerCache.class);
size = high - -128 + 1;
if (archivedCache == null || size > archivedCache.length) {
Integer[] c = new Integer[size];
int j = -128;

for(int k = 0; k < c.length; ++k) {
c[k] = new Integer(j++);
}

archivedCache = c;
}

cache = archivedCache;

assert high >= 127;

}

}

整体就是初始化一个 IntegerCache.cache 数组,数组里面存储-128到127之间的数字当做是缓存,源码一开始是分析数组长度,然后给数组赋值;
总的来说,三个重构的 valueOf() 方法还是大同小异的:

Integer valueOf(int i):返回一个表示指定的 int 值的 Integer 实例;
Integer valueOf(String s):返回保存指定的 String 的值的 Integer 对象;
Integer valueOf(String s, int radix):返回一个 Integer 对象,该对象中保存了用第二个参数提供的基数进行解析时从指定的 String 中提取的值;


后记
看源码还是能学到很多东西的,源码自有黄金屋,多看多学,夯实基础,之后会轻松高效很多!

©著作权归作者所有:来自51CTO博客作者小二上酒8的原创作品,请联系作者获取转载授权,否则将追究法律责任

@autowired和@resource到底什么区别,你明白了吗?_wx630f055ce23fc的博客-多极客编程

大家做 Java 开发的,肯定对于 Spring 是非常熟悉的,而且面试的时候,也相信大家能够非常轻易的知道这个所有的关于 Spring 的面试题,比如 Spring 的注入什么的。也肯定会被问到 @Autowired 和 @Resource 到底用哪个比较适合,今天就来讲讲这个注入的注解是个什么区别。 @Autowired @Autowired顾名思义,就是自动装配,而它的作用是为了消除代码Ja

一个注解搞定责任链,学还是不学?_wx630f055ce23fc的博客-多极客编程

背景在繁琐的业务流程处理中,通常采用面向过程的设计方法将流程拆分成N个步骤,每个步骤执行独立的逻辑。public void process(params){ doFirst(params); doSecond(params); .... doLast(params);}但是这样剥离仍然是不彻底的,修改其中一个步骤仍然可能影响其他步骤(同一个类修改,不符合开闭原则)。在这种场

【java实战】项目经验_wx630f055ce23fc的博客-多极客编程

1.慢sql优化 一般的慢sql都是由对时间范围查询造成的慢sql原型SELECT xx,xx,xxFROM xxWHERE is_deleted = ? AND status = ? AND start_time IS NOT NULL AND start_time <= now()导致慢sql的原因是AND start_time IS NOT NULL AND start_time

java 做项目能用到 list 的场景,这篇总结全了_wx630f055ce23fc的博客-多极客编程

List 代表有顺序的一组元素,顺序代表遍历元素时是有顺序的,先放进 List 的元素会先被遍历到,这点很像数组,但是跟数组很不一样的是 List 对大小没有限制。List 是使用 Java 编写程序的时候,最高频使用的数据结构,今天这篇文章我们就来好好地把List主要的使用方法过一遍,在后半部分还会给出多个特遍有用的能提高我们开发效率的实践示例,整个文章的大纲如下: List 接口List 接口

mysql之索引初识篇:索引机制、索引分类、索引使用与管理综述_wx630f055ce23fc的博客-多极客编程

由于​​MySQL​​是作为存储层部署在业务系统的最后端,所有的业务数据最终都要入库落盘,但随着一个项目在线上运行的时间越来越久,数据库中的数据量自然会越来越多,而数据体积出现增长后,当需要从表查询一些数据时,效率会越发低下。在正常情况下,表的查询性能和数据量是成反比的,也就是数据越多,查询越慢。这是什么原因导致的呢?由于​​MySQL​​默认的查询方式导致的,举个例子~SELECT * FROM

java泛型的总结_wx630f055ce23fc的博客-多极客编程

泛型可以用于接口、类、方法上。还有泛型通配符这个概念 泛型的好处:可以在编译时检查1.用于方法中,指定该方法中的形参的类型。 语法:修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ } 注意:方法上定义了是什么 泛型变量 ,后面就只能用什么 泛型变量。package com.itheima.hw;import java.util.Arrays;/** * @author Pzi

@autowired和@resource到底什么区别,你明白了吗?_wx630f055ce23fc的博客-多极客编程

大家做 Java 开发的,肯定对于 Spring 是非常熟悉的,而且面试的时候,也相信大家能够非常轻易的知道这个所有的关于 Spring 的面试题,比如 Spring 的注入什么的。也肯定会被问到 @Autowired 和 @Resource 到底用哪个比较适合,今天就来讲讲这个注入的注解是个什么区别。 @Autowired @Autowired顾名思义,就是自动装配,而它的作用是为了消除代码Ja

一个注解搞定责任链,学还是不学?_wx630f055ce23fc的博客-多极客编程

背景在繁琐的业务流程处理中,通常采用面向过程的设计方法将流程拆分成N个步骤,每个步骤执行独立的逻辑。public void process(params){ doFirst(params); doSecond(params); .... doLast(params);}但是这样剥离仍然是不彻底的,修改其中一个步骤仍然可能影响其他步骤(同一个类修改,不符合开闭原则)。在这种场

[python]分享七条有用的pip命令_ai算法之道的博客-多极客编程

1. 引言众所周知,在Python的日常学习中,我们最最经常使用的一个包就是​​pip​​,它的全称叫做​​package installer for python​​ ,直译过来就是Python包管理器,核心功能就是对Python的第三方库进行安装、更新、卸载等操作。2. 基础用法举例,在某些数学科学项目中,我们经常需要使用到例如​​pandas ​​第三方包来进行相关数据处理,此时我们一般通过

java 做项目能用到 list 的场景,这篇总结全了_wx630f055ce23fc的博客-多极客编程

List 代表有顺序的一组元素,顺序代表遍历元素时是有顺序的,先放进 List 的元素会先被遍历到,这点很像数组,但是跟数组很不一样的是 List 对大小没有限制。List 是使用 Java 编写程序的时候,最高频使用的数据结构,今天这篇文章我们就来好好地把List主要的使用方法过一遍,在后半部分还会给出多个特遍有用的能提高我们开发效率的实践示例,整个文章的大纲如下: List 接口List 接口

mysql之索引初识篇:索引机制、索引分类、索引使用与管理综述_wx630f055ce23fc的博客-多极客编程

由于​​MySQL​​是作为存储层部署在业务系统的最后端,所有的业务数据最终都要入库落盘,但随着一个项目在线上运行的时间越来越久,数据库中的数据量自然会越来越多,而数据体积出现增长后,当需要从表查询一些数据时,效率会越发低下。在正常情况下,表的查询性能和数据量是成反比的,也就是数据越多,查询越慢。这是什么原因导致的呢?由于​​MySQL​​默认的查询方式导致的,举个例子~SELECT * FROM

java泛型的总结_wx630f055ce23fc的博客-多极客编程

泛型可以用于接口、类、方法上。还有泛型通配符这个概念 泛型的好处:可以在编译时检查1.用于方法中,指定该方法中的形参的类型。 语法:修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ } 注意:方法上定义了是什么 泛型变量 ,后面就只能用什么 泛型变量。package com.itheima.hw;import java.util.Arrays;/** * @author Pzi