jdk-Integer源码解析

先看下类的介绍

/**
*{@code Integer}类包装原语类型的值
*{@code int}在一个对象中。{@code Integer}类型的对象
*包含类型为{@code int}的单个字段。
 *
*<p>此外,这个类还提供了几种转换方法
*一个{@code int}到一个{@code String},一个{@code String}到
*{@code int},以及其他在
*处理{@code int}。
 *
*<p>实现说明:“比特旋转”的实现
*方法(例如{@link#highestOneBit(int)highestOneBit})和
*{@link\numberOfTrailingZeros(int)numberOfTrailingZeros})是
*根据亨利·S·沃伦的资料
*喜悦</i>,(Addison-Wesley,2002年)。
 *
*@作者李博因顿
*@作者亚瑟·范霍夫
*@作者乔希·布洛赫
*@作者约瑟夫·达西
*@JDK1.0之后
*/

一.类的定义

public final class Integer extends Number implements Comparable<Integer>

1.Integer类被final修饰说明它无法被继承

2.Integer继承了Number类

public abstract class Number implements java.io.Serializable {
    /**
*将指定数字的值返回为{@code int},
*可能涉及舍入或截断。
     *
*@返回转换后此对象表示的数值
*键入{@code int}。
*/
    public abstract int intValue();

    /**
*将指定数字的值返回为{@code long},
*可能涉及舍入或截断。
     *
*@返回转换后此对象表示的数值
*键入{@code long}。
*/
    public abstract long longValue();

    /**
*将指定数字的值返回为{@code float},
*可能需要四舍五入。
     *
*@返回转换后此对象表示的数值
*键入{@code float}。
*/
    public abstract float floatValue();

    /**
*将指定数字的值返回为{@code double},
*可能需要四舍五入。
     *
*@返回转换后此对象表示的数值
*键入{@code double}。
*/
    public abstract double doubleValue();

    /**
*将指定数字的值返回为{@code byte},
*可能涉及舍入或截断。
     *
*<p>此实现返回{@link#intValue}cast的结果
*到{@code byte}。
     *
*@返回转换后此对象表示的数值
*键入{@code byte}。
*@从JDK1.1开始
*/
    public byte byteValue() {
        return (byte)intValue();
    }

    /**
*将指定数字的值返回为{@code short},
*可能涉及舍入或截断。
     *
*<p>此实现返回{@link#intValue}cast的结果
*致{@code short}。
     *
*@返回转换后此对象表示的数值
*键入{@code short}。
*@从JDK1.1开始
*/
    public short shortValue() {
        return (short)intValue();
    }

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -8742448824652078965L;
}

Number类是一个抽象类,里面定义了一些数值类型转换的抽象方法。Number类型实现了java.io.Serializable接口支持序列化

3.Integer实现了Comparable接口支持通过compareTo方法比较数值大小

二.类的属性

  /**
*保持{@code int}所能达到的最小值的常数
*有-2<sup>31<sup>。
*/
    @Native public static final int   MIN_VALUE = 0x80000000;

    /**
*保持{@code int}所能达到的最大值的常数
*有,2<sup>31<sup>-1。
*/
    @Native public static final int   MAX_VALUE = 0x7fffffff;

    /**
*表示原语类型的{@code Class}实例
*{@code int}。
     *
*@从JDK1.1开始
*/
    @SuppressWarnings("unchecked")
    public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");

    /**
*将数字表示为字符串的所有可能字符
*/
    final static char[] digits = {
        '0' , '1' , '2' , '3' , '4' , '5' ,
        '6' , '7' , '8' , '9' , 'a' , 'b' ,
        'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
        'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
        'o' , 'p' , 'q' , 'r' , 's' , 't' ,
        'u' , 'v' , 'w' , 'x' , 'y' , 'z'
    };

三.类的构造方法

*@param value要由
*{@code Integer}对象。
*/
    public Integer(int value) {
        this.value = value;
    }

    /**
*构造新分配的{@code Integer}对象
*表示由
*{@code String}参数。字符串转换为
*{@code int}值与
*基数10的{@code parseInt}方法。
     *
*@param s要转换为
*{@code Integer}。
*如果{@code String}没有
*包含可解析整数。
*@看java.lang.Integer#解析(java.lang.String语言,内景)
*/
    public Integer(String s) throws NumberFormatException {
        this.value = parseInt(s, 10);
    }

四.类的常用方法

1. public static int parseInt(String s) throws NumberFormatException

    /**
*将字符串参数解析为带符号的十进制整数。这个
*字符串中的字符都必须是十进制数字,但
*第一个字符可以是ASCII减号{@code'-'}
*({@code'\u002D'})表示负值或
*ASCII加号{@code'+'}({@code'\u002B'})到
*表示正值。得到的整数值是
*返回,就好像参数和基数10是
*作为{@link#parseInt的参数给定(java.lang.String语言,
*int)}方法。
     *
*@param s a{@code String}包含{@code int}
*要分析的表示
*@返回由十进制参数表示的整数值。
*@exception NumberFormatException如果字符串不包含
*可分解整数。
*/
    public static int parseInt(String s) throws NumberFormatException {
        return parseInt(s,10);
    }
// 字符串转int 方法,可以看到接下去调用的是parseInt(s,10)我们往下看下这个方法



   /**
*将字符串参数解析为基数中的有符号整数
*由第二个参数指定。字符串中的字符
*必须都是指定基数的位数(由
*是否{@linkjava.lang.Character#数字(char,int)}返回
*非负值),但第一个字符可能是
*ASCII减号{@code'-'}({@code'\u002D'})到
*表示负值或ASCII加号{@code'+'}
*({@code'\u002B'})表示正值。这个
*返回结果整数值。
     *
*<p>类型{@code NumberFormatException}的异常是
*如果发生以下任何情况,则抛出:
*<ul>
*<li>第一个参数是{@code null}或是
*长度为零。
     *
*<li>基数小于
*{@链接java.lang.Character最小基数}或者
*大于{@linkjava.lang.Character最大基数}.
     *
*<li>字符串的任何字符都不是指定的
*基数,除了第一个字符可以是负号
*{@code'-'}({@code'\u002D'})或加号
*{@code'+'}({@code'\u002B'})前提是
*字符串长度超过1。
     *
*<li>字符串表示的值不是类型的值
*{@code int}。
*</ul>
     *
*<p>示例:
*<blockquote><pre>
*parseInt(“0”,10)返回0
*parseInt(“473”,10)返回473
*parseInt(“+42”,10)返回42
*parseInt(“-0”,10)返回0
*parseInt(“-FF”,16)返回-255
*parseInt(“1100110”,2)返回102
*parseInt(“2147483647”,10)返回2147483647
*parseInt(“-2147483648”,10)返回-2147483648
*parseInt(“2147483648”,10)引发NumberFormatException
*parseInt(“99”,8)引发NumberFormatException
*parseInt(“Kona”,10)引发NumberFormatException
*parseInt(“Kona”,27)返回411787
*</pre></blockquote>
     *
*@param s包含整数的{@code String}
*要分析的表示
*@param基数分析{@code s}时要使用的基数。
*@返回
*指定基数。
*@exception NumberFormatException如果{@code String}
*不包含可解析的{@code int}。
*/
    

public static int parseInt(String s, int radix) throws NumberFormatException {

        //判断s是否为null
        if (s == null) {
            throw new NumberFormatException("null");
        }

        //判断进制是否在 2~36之间
        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; //判断是否为负数,false代表正数,true代表负数
            int i = 0;//相当于一个指针,指向字符串Sring的位数进行检测
            int len = s.length();//字符串长度

            //limit 默认初始化为 最大正整数的负数 ,假如字符串表示的是正数,
            //那么result(在返回之前一直是负数形式)就必须和这个最大正数的负数来比较,判断是否溢出
            int limit = -2147483647;

            //如果传入字符串长度<=0,报异常退出
            if (len <= 0) {
                throw NumberFormatException.forInputString(s);
            }
            //如果>0,继续运行
            else {
                //取出字符串第一个字符
                char firstChar = s.charAt(0);
                //判断第一个字符是否是数字
                if (firstChar < '0') {
                    //如果第一个字符是负号
                    if (firstChar == '-') {
                        negative = true;        //判断正负字段转为true
                        limit = -2147483648;    //在负号的情况下,判断溢出的值就变成了整数的最小负数了
                    }
                    //如果第一个字符不是负号,也不是正号
                    else if (firstChar != '+') {
                        throw NumberFormatException.forInputString(s);    //无法转换,报异常退出
                    }
                    //如果string长度仅为1,第一个又不是数字,正负号,直接报异常退出
                    if (len == 1) {
                        throw NumberFormatException.forInputString(s);
                    }

                    ++i;//字符串第一个数字验证完毕,指针向右移动一位
                }
                
                //这个是用来判断当前的 result 在接受下一个字符串位置的数字后会不会溢出
                int multmin = limit / radix;

                //存放最终返回结果的负数值,如果本身和就是负数,则就是原数
                int result;
                //根据i指针获取到每一个数值,存储到digit中
                int digit;
                for (result = 0; i < len; result -= digit) {
                    //获取到i指针所指向的字符,存放到dighit,之后i加一
                    digit = Character.digit(s.charAt(i++), radix);
                    //如果获取到的字符<0或者结果<最小值溢出,报异常退出
                    //result < multmin,说明result * radix 后还比 limit 小
                    if (digit < 0 || result < multmin) {
                        throw NumberFormatException.forInputString(s);
                    }


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

                //如果negative为true,说明返回的数为负数,直接返回result即可
                //如果negative为false,说明返回的数为正数,返回result的相反数
                return negative ? result : -result;
            }
        }
    }
}

parseInt(String s)方法底层调用的是parseInt(String s, int radix) 方法这个方法是指将radix进制表示的字符串数字转化为10进制表示

2. public static Integer valueOf(String s) throws NumberFormatException

    /**
*返回一个{@code Integer}对象,该对象包含
*指定的{@code String}的值。争论是
*解释为表示有符号的十进制整数
*好像参数是给{@链接的
*#解析(java.lang.String语言)}方法。结果是
*{@code Integer}表示整数值的对象
*由字符串指定。
     *
*换句话说,这个方法返回{@code Integer}
*对象的值等于:
     *
*<blockquote>
*{@code新整数(整数.parseInt(s) )}
*</blockquote>
     *
*@param s要解析的字符串。
*@返回一个{@code Integer}对象,该对象包含该值
*由字符串参数表示。
*@exception NumberFormatException如果无法分析字符串
*作为整数。
*/
    public static Integer valueOf(String s) throws NumberFormatException {
        return Integer.valueOf(parseInt(s, 10));
    }

// 接着调用如下方法

  /**
*返回一个{@code Integer}实例,表示指定的
*{@code int}值。如果新的{@code Integer}实例不是
*需要时,通常应优先使用此方法
*构造函数{@link#Integer(int)},因为此方法很可能
*通过
*缓存频繁请求的值。
     *
*此方法将始终缓存-128到127之间的值,
*包含,并且可以缓存此范围之外的其他值。
     *
*@param i an{@code int}值。
*@返回表示{@code i}的{@code Integer}实例。
*@从1.5开始
*/
    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(包括)根据JLS的要求。
     *
*缓存在首次使用时初始化。缓存的大小
*可以由{@code-XX:AutoBoxCacheMax=<size>}选项控制。
*在虚拟机初始化期间,java.lang.Integer语言.整数缓存高财产
*可以设置并保存在
* 太阳杂项虚拟机上课。
*/

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

        static {
//高值可以由属性配置
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
//最大数组大小为Integer.MAX_值
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
//如果无法将属性解析为int,请忽略它。
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

//范围[-128,127]必须实习(JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

这个方法的关键点是用到了IntegerCache缓存,默认缓存了-128~127的Integer

3. public String toString()

   /**
*返回一个{@code String}对象,表示
*{@code Integer}的值。值转换为带符号的
*十进制表示并作为字符串返回,就像
*整数值作为{@链接的参数给出
* java.lang.Integer#toString(int)}方法。
     *
*@返回此对象值的字符串表示形式
*基数10。
*/
    public String toString() {
        return toString(value);
    }


    /**
*返回一个{@code String}对象,表示
*指定的整数。参数转换为带符号的十进制
*表示并作为字符串返回,就像
*参数和基数10作为{@link的参数给出
*#toString(int,int)}方法。
     *
*@param i要转换的整数。
*@返回以10为基数的参数的字符串表示形式。
*/
    public static String toString(int i) {
        if (i == Integer.MIN_VALUE)
            return "-2147483648";
        int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
        char[] buf = new char[size];
        getChars(i, size, buf);
        return new String(buf, true);
    }

  /**
*将表示整数i的字符放入
*字符数组buf。字符被放入
*从最低有效值开始的缓冲区向后
*指定索引处的数字(不包括)和工作
*从那里往后。
     *
*如果我=整数最小值
*/
    static void getChars(int i, int index, char[] buf) {
        int q, r;
        int charPos = index;
        char sign = 0;

        if (i < 0) {
            sign = '-';
            i = -i;
        }

//每次迭代生成两位数
        while (i >= 65536) {
            q = i / 100;
//真的:r=i-(q*100);
            r = i - ((q << 6) + (q << 5) + (q << 2));
            i = q;
            buf [--charPos] = DigitOnes[r];
            buf [--charPos] = DigitTens[r];
        }

//对于较小的数字,切换到快速模式
//断言(i<=65536,i);
        for (;;) {
            q = (i * 52429) >>> (16+3);
            r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...
            buf [--charPos] = digits [r];
            i = q;
            if (i == 0) break;
        }
        if (sign != 0) {
            buf [--charPos] = sign;
        }
    }

toString() 是查找出value中各个数字对应的字符,然后拼成字符串

4.equals方法

    /**
*将此对象与指定对象进行比较。结果是
*{@code true}如果且仅当参数不是
*{@code null}并且是一个{@code Integer}对象
*包含与此对象相同的{@code int}值。
     *
*@param obj要与之比较的对象。
*如果对象相同,@return{@code true};
*{@code false}否则。
*/
    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

Integer 重写了equals方法也重写了hashcode方法

五.常见面试题

1.Integer 占几个字节?

4个

2.Integer的数值范围

-2的31次方到2的31次方减一

3.Integer和int的区别

Integer是java包装类型是对象用一个引用指向这个对象,int是基本类型。

基本数据类型存放位置:

    方法参数、局部变量存放在栈内存中的栈桢中的局部变量表

     常量存放在常量池中

Integer存放位置:

    常量池、堆内存

4.

public static void main(String[] args) {
        Integer a = 100;
        Integer b = 100;
        Integer c = 200;
        Integer d = 200;
        Integer e = new Integer(100);
        Integer f = Integer.valueOf(100);
        System.out.println(a == b);
        System.out.println(c == d);
        System.out.println(a == e);
        System.out.println(a == f);
    }

判断上述代码的运行结果

结果如下:

Connected to the target VM, address: '127.0.0.1:50048', transport: 'socket'
true
false
false
true

原因是int 转 Integer是自动装箱,自动装箱调用的就是Integer.valueof()方法,由于Integer.valueof方法中对-127~128的数据进行了缓存,所以1,4相等,而2,3不等

5.Integer中缓存范围是否可以修改

下限不能修改,上限可以通过设置java.lang.Integer.IntegerCache.high修改

六.引申

Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。

Double、Float的valueOf方法的实现是类似的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值