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

Integer:

  继承结构:

  -java.lang.Object

    --java.lang.Number

      ---java.lang.Integer

  其中父类Number是个抽象类,是所有数字类型相关的类的父类,例如DoubleFloatIntegerLongShort。

  Integer类还实现了Comparable接口用以比较两个Integer的大小。

//源码
public final class Integer extends Number implements Comparable<Integer>

  Integer类中规定了范围大小时在-2^31~2^31-1之间。

    //源码/*** A constant holding the minimum value an {@code int} can* have, -2<sup>31</sup>.*/@Native public static final int   MIN_VALUE = 0x80000000;/*** A constant holding the maximum value an {@code int} can* have, 2<sup>31</sup>-1.*/@Native public static final int   MAX_VALUE = 0x7fffffff;

  另外还有用来以二进制补码形式表示 int 值的比特位数的SIZE字段,表示基本类型 intClass 实例的TYPE字段。

  内部方法实现:

  Integer大概实现了四五十个方法,下面结合源码分析一下平时常用又比较重要的几个方法。

  首先构造一个Integer对象,Integer的构造方法非常简单直接传入一个int或者string即可。传入int是直接赋值给value字段保存。传入string是先把s通过parseInt方法转换成十进制int再赋值给value字段。

    //源码public Integer(int value) {this.value = value;}public Integer(String s) throws NumberFormatException {this.value = parseInt(s, 10);}

  接下来看一下这个不简单的parseInt方法。

  从方法签名就可以看出这个方法的作用是把传入的字符串s解析单做radix机制的字串来解析成十进制int值。并进行了一些异常处理。举个栗子:

     parseInt("0", 10) returns 0parseInt("473", 10) returns 473parseInt("+42", 10) returns 42parseInt("-0", 10) returns 0parseInt("-FF", 16) returns -255parseInt("1100110", 2) returns 102parseInt("2147483647", 10) returns 2147483647parseInt("-2147483648", 10) returns -2147483648parseInt("2147483648", 10) throws a NumberFormatExceptionparseInt("99", 8) throws a NumberFormatExceptionparseInt("Kona", 10) throws a NumberFormatExceptionparseInt("Kona", 27) returns 411787

  下面来看一下具体实现(为了更清楚的分析实现过程,文字都作为注释写在源代码里了):

  //源码,限于篇幅简化了源码格式。public static int parseInt(String s, int radix) throws NumberFormatException {//这里有这个警告是因为valueOf方法使用了parseInt方法和IntegerCache对象,//因为valueOf在IntegerCache初始化之前使用导致异常情况。后面会详细分析。/** WARNING: This method may be invoked early during VM initialization* before IntegerCache is initialized. Care must be taken to not use* the valueOf method.*///下面三个if用来判断参数是否合法。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");}int result = 0; //解析结果boolean negative = false; //是否是负数int i = 0, len = s.length(); //索引变量和字符串长度int limit = -Integer.MAX_VALUE; //最大值限制int multmin; //基数下的最小值int digit; //记录每一位的数字if (len > 0) {char firstChar = s.charAt(0);if (firstChar < '0') { // 判断是否带‘+’或‘-’if (firstChar == '-') {negative = true;limit = Integer.MIN_VALUE;} else if (firstChar != '+')throw NumberFormatException.forInputString(s);if (len == 1) // 格式非法,含有除了‘+’‘-’之外的字符。throw NumberFormatException.forInputString(s);i++;}multmin = limit / radix;while (i < len) {//利用了Character类中的digit非法,作用是解析一个字符。digit = Character.digit(s.charAt(i++),radix);//进行异常判断。//这个解析字符串为数字的算法和平时想到的不太一样,是从字符串左边开始,初始化结果是0,//其实是把结果算成负的,返回的时候再转回来。result -= digit;if (digit < 0) {throw NumberFormatException.forInputString(s);}if (result < multmin) {throw NumberFormatException.forInputString(s);}result *= radix;if (result < limit + digit) {throw NumberFormatException.forInputString(s);}result -= digit;}} else {throw NumberFormatException.forInputString(s);}return negative ? result : -result; //如果是负的就直接返回,因为算出来的已经是负数。}

  平时经常使用的Integer.parseInt(String s)也是基于这个方法实现的。只不过默认radix为10.

  //源码    public static int parseInt(String s) throws NumberFormatException {return parseInt(s,10);}

  接下来就来分析一下上面提到的,valueOf方法。一共有三个valueOf方法,只是传参不同。其中有两个的内部实现是依据valueOf(int i)和parseInt(String s, int radix)来实现的。

//源码public static Integer valueOf(String s, int radix) throws NumberFormatException {return Integer.valueOf(parseInt(s,radix));}
public static Integer valueOf(String s) throws NumberFormatException {return Integer.valueOf(parseInt(s, 10));}

那就来分析一下valueOf(int i)方法就好了。

  //源码  public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}

可以看到这里使用到了IntegerCache缓存,IntegerCache默认缓存-128~127之间的Integer。IntegerCache是Integer类的静态内部类。

//源码
private static class IntegerCache {static final int low = -128; //默认low=-128static final int high; //high可以配置,通过 VM 参数-XX:AutoBoxCacheMax=<size>//high可以配置,所以默认缓存-128~127,但是也可以缓存另外的常用数。static final Integer cache[]; //缓存数组//静态代码块,Integer类加载时就缓存。static {// high value may be configured by propertyint h = 127; //默认127String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); //读取VM参数配置。if (integerCacheHighPropValue != null) {try {int i = parseInt(integerCacheHighPropValue);i = Math.max(i, 127); //缓存大数// Maximum array size is Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1); //防止越界} catch( NumberFormatException nfe) {// If the property cannot be parsed into an int, ignore it.
            }}high = h;cache = new Integer[(high - low) + 1]; //创建缓存数组。int j = low;for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++); //缓存。// range [-128, 127] must be interned (JLS7 5.1.7)assert IntegerCache.high >= 127; //保证[-128, 127]在缓存范围内。
    }private IntegerCache() {}
}

下面看一段测试代码:

    //首先要明确一点,对象之间的==是比较内存地址,常数之间的比较是数值比较。  public static void main(String[] args) {Integer num1 = new Integer(100);Integer num2 = new Integer(100);System.out.println(num1 == num2);//false,因为这两个对象是独立创建的,有自己的内存空间和地址。Integer num3 = 100;Integer num4 = 100;System.out.println(num3 == num4);//true,常数之间比较数值。Integer num5 = 128;Integer num6 = 128;System.out.println(num5 == num6);//false,自动装箱成对象,但是超过了默认的缓存范围,同第一个。如果是127就是true。Integer num7 = 100;Integer num8 = new Integer(100);System.out.println(num7 == num8);//false,两个对象之间比较内存地址,不同的是num7通过自动装箱调用valueOf方法,指向缓存的100,而num8是指向自己内存空间里的100.int num9 = 100;Integer num10 = new Integer(100);     System.out.println(num9 == num10);//true,Integer对象和int比较时,Integer会自动拆箱(intValue方法)成为int,变成两个数值比较。Integer num11 = 100;System.out.println(num9 == num11);//true,num11通过自动装箱调用valueOf方法指向缓存中的100,比较的时候缓存中的100对象自动拆箱成为数值100.}

  如果没有认真研究过Integer的缓存机制和自动拆箱装箱机制的话,这个程序的运行结果绝对会让你出乎意料。理解之后就OK了。

  理解这个缓存机制也是非常重要的,因为如果程序中因为这个出现了bug那么如果不知道缓存机制估计到死也调不出来。

  这里说一下关于Long,Short是和Integer机制类似,只不过不支持high的配置。Double,Float是没有缓存机制的,因为即使是-128~127之间的浮点数接近无穷大。

  这一次的Integer类的源码分析就到这里,Integer类里还有一些关于反码、补码计算等位运算的方法。如果有兴趣或者开发中用到再来研究。

转载于:https://www.cnblogs.com/wxisme/p/6308517.html

JDK源码分析-Integer相关推荐

  1. 【JDK】JDK源码分析-HashMap(1)

    概述 HashMap 是 Java 开发中最常用的容器类之一,也是面试的常客.它其实就是前文「数据结构与算法笔记(二)」中「散列表」的实现,处理散列冲突用的是"链表法",并且在 J ...

  2. 【JDK】JDK源码分析-CountDownLatch

    概述 CountDownLatch 是并发包中的一个工具类,它的典型应用场景为:一个线程等待几个线程执行,待这几个线程结束后,该线程再继续执行. 简单起见,可以把它理解为一个倒数的计数器:初始值为线程 ...

  3. JDK源码解析 Integer类使用了享元模式

    JDK源码解析 Integer类使用了享元模式. 我们先看下面的例子: public class Demo {public static void main(String[] args) {Integ ...

  4. JDK源码分析(2)LinkedList

    JDK版本 LinkedList简介 LinkedList 是一个继承于AbstractSequentialList的双向链表.它也可以被当作堆栈.队列或双端队列进行操作. LinkedList 实现 ...

  5. StringBuffer类【JDK源码分析】

    StringBuffer类[JDK源码分析] 前言 推荐 说明 StringBuffer类 基本信息 属性 构造方法 部分方法 length capacity append insert revers ...

  6. JDK源码分析 NIO实现

    总列表:http://hg.openjdk.java.net/ 小版本:http://hg.openjdk.java.net/jdk8u jdk:http://hg.openjdk.java.net/ ...

  7. jdk源码分析书籍 pdf_如何阅读源码?

    点击上方"IT牧场",选择"设为星标" 技术干货每日送达! 阅读源码是每个优秀开发工程师的必经之路,那么这篇文章就来讲解下为什么要阅读源码以及如何阅读源码. 首 ...

  8. JDK源码分析 FutureTask源码分析

    文章目录 前言 一.Callable接口 二.Future接口 三.FutureTask源码分析 3.1 Future继承结构图 3.2 参数介绍 3.3 构造函数 3.4. FutureTask的A ...

  9. JDK源码分析实战系列-PriorityQueue

    完全二叉树 一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下.从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树 ...

最新文章

  1. 解决SSH连接出现 Software caused connection abort 的问题
  2. 访问控制 - C++快速入门18
  3. Javascript自定义事件功能与用法实例分析
  4. 实验3 动态规划(0/1背包)
  5. SQL Server CONVERT() 函数,Date 函数
  6. [PAT乙级]1004 成绩排名
  7. 在.NET中使用SMTP发送邮件
  8. Andros系列排爆机器人原理_中国製造2025系列M之二:高档数控机床和机器人
  9. mysql新用户不能创建数据库中_MYSQL添加新用户 MYSQL为用户创建数据库 MYSQL为新用户分配权限...
  10. CUDA——Windows上CUDA的安装教程
  11. Spring基础精华知识点
  12. paip.提升性能--- mysql 建立索引 删除索引 很慢的解决.
  13. 深入浅出通信原理知识点10
  14. win10下Clion的安装与配置
  15. 关于西门子STEP7 在Windows10安装的一些心得
  16. MySQL数据库增删改查的SQL语句
  17. 高通modem命名及对应芯片
  18. linux 查看opengl版本,如何使用optirun检查Linux系统上支持哪个版本的OpenGL?
  19. PAT1003 我要通过! (20 分)(C语言)
  20. angular7中使用jsonViewer

热门文章

  1. EGO首次线下活动分享:Facebook研发团队的高效秘诀
  2. STL六大组件:分配器、容器、迭代器、算法、仿函数、适配器
  3. FFT2 图像二维FFT含义解释
  4. DHCP服务器在企业网中的应用
  5. Visual C++ 2011-8-15
  6. 前端每日实战:143# 视频演示如何用 CSS 的 Grid 布局创作一枚小松鼠邮票
  7. Python最简编码规范
  8. Docker了解(官方解读)
  9. 如何用zendstudio新建一个PHP工程
  10. Java刷题知识点之进程和线程的区别