Integer和Long的java中使用特别广泛,本人主要一下Integer.toString(int i)和Long.toString(long i)方法,其他方法都比较容易理解。

Integer.toString(int i)和Long.toString(long i),以Integer.toString(int i)为例,先看源码:

  1. /**
  2. * Returns a {@code String} object representing the
  3. * specified integer. The argument is converted to signed decimal
  4. * representation and returned as a string, exactly as if the
  5. * argument and radix 10 were given as arguments to the {@link
  6. * #toString(int, int)} method.
  7. *
  8. * @param i an integer to be converted.
  9. * @return a string representation of the argument in base 10.
  10. */
  11. public static String toString(int i) {
  12. if (i == Integer.MIN_VALUE)
  13. return "-2147483648";
  14. int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
  15. char[] buf = new char[size];
  16. getChars(i, size, buf);
  17. return new String(buf, true);
  18. }

通过调用stringSize来计算i的长度,也就是位数,用来分配合适大小的字符数组buf,然后调用getChars来设置buf的值。

stringSize的Integer和Long中的实现有所不同,先看看源码

Integer.stringSize(int x)源码:

  1. final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
  2. 99999999, 999999999, Integer.MAX_VALUE };
  3.  
  4. // Requires positive x
  5. static int stringSize(int x) {
  6. for (int i=0; ; i++)
  7. if (x <= sizeTable[i])
  8. return i+1;
  9. }

将数据存放在数组中,数组中的下标+1就是i的长度,当x小于sizeTable中的某个值时,这样设计只需要循环就可以得出长度,效率高。

Long.stringSize(long x)源码:

  1. // Requires positive x
  2. static int stringSize(long x) {
  3. long p = 10;
  4. for (int i=1; i<19; i++) {
  5. if (x < p)
  6. return i;
  7. p = 10*p;
  8. }
  9. return 19;
  10. }

因为Long的十进制最大长度是19,在计算长度时通过反复乘以10的方式求出来的,可能会问为什么不用Integer.stringSize(int x)的方法,我也没有找到合适的解释。

传统的方案可能是通过反复除以10的方法求出来的,但是这样的效率低,因为计算机在处理乘法时要比除法快。

getChars(int i, int index, char[] buf)源码:

  1. /**
  2. * Places characters representing the integer i into the
  3. * character array buf. The characters are placed into
  4. * the buffer backwards starting with the least significant
  5. * digit at the specified index (exclusive), and working
  6. * backwards from there.
  7. *
  8. * Will fail if i == Integer.MIN_VALUE
  9. */
  10. static void getChars(int i, int index, char[] buf) {
  11. int q, r;
  12. int charPos = index;
  13. char sign = 0;
  14.  
  15. if (i < 0) {
  16. sign = '-';
  17. i = -i;
  18. }
  19.  
  20. // Generate two digits per iteration
  21. while (i >= 65536) {
  22. q = i / 100;
  23. // really: r = i - (q * 100);
  24. r = i - ((q << 6) + (q << 5) + (q << 2));
  25. i = q;
  26. buf [--charPos] = DigitOnes[r];
  27. buf [--charPos] = DigitTens[r];
  28. }
  29.  
  30. // Fall thru to fast mode for smaller numbers
  31. // assert(i <= 65536, i);
  32. for (;;) {
  33. q = (i * 52429) >>> (16+3);
  34. r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
  35. buf [--charPos] = digits [r];
  36. i = q;
  37. if (i == 0) break;
  38. }
  39. if (sign != 0) {
  40. buf [--charPos] = sign;
  41. }
  42. }

这是整个转换过程的核心代码,首先确定符号,其次当i>=65536时将i除以100,并且通过DigitOnes[r]和DigitTens[r]来获取十位和个位上的值,因为除法慢,所以一次性除以100提高效率,DigitOnes和DigitTens如下:

  1. final static char [] DigitTens = {
  2. '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
  3. '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
  4. '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
  5. '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
  6. '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
  7. '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
  8. '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
  9. '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
  10. '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
  11. '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
  12. } ;
  13.  
  14. final static char [] DigitOnes = {
  15. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  16. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  17. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  18. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  19. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  20. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  21. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  22. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  23. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  24. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  25. } ;

假设r=34,通过查表可以得出DigitOnes[r]=4,DigitTens[r]=3。

q = (i * 52429) >>> (16+3); 的本质是将i/10,并去掉小数部分,219=524288,52429/524288=0.10000038146972656,为什么会选择52429/524288呢,看了下面就知道了:

  1. 2^10=1024, 103/1024=0.1005859375
  2. 2^11=2048, 205/2048=0.10009765625
  3. 2^12=4096, 410/4096=0.10009765625
  4. 2^13=8192, 820/8192=0.10009765625
  5. 2^14=16384, 1639/16384=0.10003662109375
  6. 2^15=32768, 3277/32768=0.100006103515625
  7. 2^16=65536, 6554/65536=0.100006103515625
  8. 2^17=131072, 13108/131072=0.100006103515625
  9. 2^18=262144, 26215/262144=0.10000228881835938
  10. 2^19=524288, 52429/524288=0.10000038146972656

可以看出52429/524288的精度最高,并且在Integer的取值范围内。

r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ... 用位运算而不用乘法也是为了提高效率。

注:以上分析内容仅个人观点(部分参考网上),如有不正确的地方希望可以相互交流。

Integer和Long部分源码分析的更多相关文章

  1. Integer面试连环炮以及源码分析

    场景:   昨天有位朋友去面试,我问他面试问了哪些问题,其中问了Integer相关的问题,以下就是面试官问的问题,还有一些是我对此做了扩展. 问:两个new Integer 128相等吗? 答:不.因 ...

  2. Integer面试连环炮以及源码分析(转)

    场景:   昨天有位朋友去面试,我问他面试问了哪些问题,其中问了Integer相关的问题,以下就是面试官问的问题,还有一些是我对此做了扩展. 问:两个new Integer 128相等吗? 答:不.因 ...

  3. JDK源码分析-Integer

    Integer是平时开发中最常用的类之一,但是如果没有研究过源码很多特性和坑可能就不知道,下面深入源码来分析一下Integer的设计和实现. Integer: 继承结构: -java.lang.Obj ...

  4. 设计模式(十二)——享元模式(Integer缓冲池源码分析)

    1 展示网站项目需求 小型的外包项目,给客户 A 做一个产品展示网站,客户 A 的朋友感觉效果不错,也希望做这样的产品展示网站,但是要求都有些不同: 1) 有客户要求以新闻的形式发布 2) 有客户人要 ...

  5. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  6. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  7. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  8. MyCat源码分析系列之——结果合并

    更多MyCat源码分析,请戳MyCat源码分析系列 结果合并 在SQL下发流程和前后端验证流程中介绍过,通过用户验证的后端连接绑定的NIOHandler是MySQLConnectionHandler实 ...

  9. MyCat源码分析系列之——BufferPool与缓存机制

    更多MyCat源码分析,请戳MyCat源码分析系列 BufferPool MyCat的缓冲区采用的是java.nio.ByteBuffer,由BufferPool类统一管理,相关的设置在SystemC ...

随机推荐

  1. (二)MySQL8.0(ZIP)、SQLyog安装

    一.mysql8.0(ZIP)的安装 安装时看了很多的文章,开始选择的是客户端安装后一直安装失败,就选择了zip安装. 注意:该方法仅适用于8.0版本安装,其余版本未测试 1.下载zip压缩包(两个都 ...

  2. foreach 集合又抛经典异常了,这次一定要刨根问底

    一:背景 1. 讲故事 最近同事在写一段业务逻辑的时候,程序跑起来总是报:集合已修改:可能无法执行枚举操作,硬是没有找到什么情况下会导致这个异常产生,就让我来找一下bug,其实这个异常在座的每个程序员 ...

  3. ida 调试android之路

    系统: Mac OSX 调试环境:IDA7.0,  adb 手机环境:红米手机 android 4.4.4 前提条件: 红米手机root之路:https://www.cnblogs.com/dzqdz ...

  4. docker镜像瘦身思路

    docker镜像瘦身思路 一.简介 docker镜像太大,带来了以下几个问题: 存储开销 这块影响其实不算很大,因为对服务器磁盘来说,15GB的存储空间并不算大,除非用户服务器的磁盘空间很紧张 部署时 ...

  5. 什么了解suite集合实现

    Testsuite继承BaseTestSuite其实内部的东西不是太多--生成suite集合的逻辑主要如下-我这里没有扒源码-因为他最终生成的TestsSuite关联的模块比较多--如果贴源码出来-- ...

  6. Linux下如何查看硬件信息?

    我们在 Linux 下进行开发时,有时也需要知道当前的硬件信息,比如:CPU几核?使用情况?内存大小及使用情况?USB设备是否被识别?等等类似此类问题.下面良许介绍一些常用的硬件查看命令. lshw ...

  7. JVM对算术运算做了什么??

    java可以进行数字的加减乘除,但是JVM的运算步骤是什么样子呢?从一个神奇的式子入手,研究下JVM到底做了什么? 先看下图:

  8. 解决start.spring.io无法访问的情况

    将start.spring.io替换成下列网址 http://start.jetbrains.org.cn/ 或者----> 连接手机热点 因为绝大多数无法访问都是因为网络问题

  9. ceph bluestore与 filestore 数据存放的区别

    一. filestore 对象所在的PG以文件方式放在xfs文件中 1 查看所有的osd硬盘,跟其他linux其他硬盘一样,被挂载一个目录中. [root@hz-storage1 ~]# df -h ...

  10. P1131 [ZJOI2007]时态同步【树形dp】

    时态同步 从叶子到根节点统计修改次数.树形\(dp\)思想. 题目描述 小\(Q\)在电子工艺实习课上学习焊接电路板.一块电路板由若干个元件组成,我们不妨称之为节点,并将其用数字\(1,2,3-\). ...