jdk源码解读-Integer

本文详细解析了Java中Integer类的定义、成员变量、静态内部类、构造方法及重要方法如parseInt、toString、valueOf等的功能与实现原理。同时,探讨了自动装箱与拆箱的过程及其在代码中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 类定义

Integer类定义如下:

public final class Integer extends Number implements Comparable<Integer> {}
  1. final修饰

  2. 继承NumberNumber是一个抽象类,Integer重写了其中的方法,这些方法作用就是各种包装类直接的转换(不包括Char

    在这里插入图片描述

  3. 实现Comparable接口,重写compareTo方法,该方法调用了Integer自己的compare方法

        public int compareTo(Integer anotherInteger) {
            return compare(this.value, anotherInteger.value);
        }
    

2. 成员变量

​ MIN_VALUE=-231

​ MAX_VALUE=231-1

​ value:实际存放数据的地方,本质是一个基本类型 int

​ SIZE:32位

​ BYTES:4字节

​ 还有像digitsDigitsTensSizeTable主要是在某些方法中有使用到,用的不多

3. 静态内部类IntegerCache

该类的作用是在程序启动的时候,创建-128~127(可通过设置虚拟机参数-Djava.lang.Integer.IntegerCache.high来更改)的Integer实例,这样起到一个缓存的作用,下面的自动拆箱装箱例子中,也会有涉及。

4. 构造方法

构造方法有两种:

4.1 传入参数为int

    public Integer(int value) {
        this.value = value;
    }

4.2 传入参数为String

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

parseInt具体代码在下文有分析。parseInt不是自动装箱的方法,valueOf才是!

5. 重要方法

5.1 parseInt

解读看注释。

  public static int parseInt(String s, int radix)
                throws NumberFormatException
    {
        /*
         * 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 (s == null) {//要转变成int的字符串s为null,抛出异常
            throw new NumberFormatException("null");
        }

        if (radix < Character.MIN_RADIX) {//进制radix 小于 最小进制2 ,抛出异常
            throw new NumberFormatException("radix " + radix +
                                            " less than Character.MIN_RADIX");
        }

        if (radix > Character.MAX_RADIX) {//进制radix 大于 最大进制36 ,抛出异常
            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); //获取字符串s的第一个字符,用于判断正负
             //这里主要用来判断第一个字符是"+"或者"-",因为这两个字符的 ASCII码都小于字符'0'
            if (firstChar < '0') { // Possible leading "+" or "-"
                if (firstChar == '-') {
                    //如果第一个字符为 - ,标志位negative=true,表示是负数,limit = Integer.MIN_VALUE,数的限制为最小值
                    negative = true;
                    limit = Integer.MIN_VALUE;
                } else if (firstChar != '+')
                    //如果第一个字符是不是 '+',直接抛出异常
                    throw NumberFormatException.forInputString(s);

                if (len == 1) // Cannot have lone "+" or "-"
                    //待转换字符长度是1,不能是单独的"+"或者"-",否则抛出异常
                    throw NumberFormatException.forInputString(s);
                i++;//i++也就是定位到第二个字符了,对于第一个字符为 + 的不作处理,按照正数来处理了
            }
            multmin = limit / radix;
            //通过不断循环,将字符串除掉第一个字符之后,根据进制不断相乘在相加得到一个正整数
            //parseInt("123",10) = 1*10的2次方+2*10+3*1 
            while (i < len) {
                // Accumulating negatively avoids surprises near MAX_VALUE
                digit = Character.digit(s.charAt(i++),radix);
                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;
    }

5.2 toString

有三个重载的toString方法,toString() toString(int i) toString(int i, int radix),关注第二个就可以了

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);
}

主要注意Integer的另外两个方法,stringSizegetChars,其中getChars不做解读了,就是转换成char字符

    final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                      99999999, 999999999, Integer.MAX_VALUE };

    // Requires positive x
    static int stringSize(int x) {
        for (int i=0; ; i++)
            if (x <= sizeTable[i])
                return i+1;
    }

stringSize()它是用来计算参数i的位数也就是转成字符串之后的字符串的长度,内部结合一个已经初始化好的int类型的数组sizeTable来完成这个计算。在stringSize中实现的形式很巧妙。注意负数包含符号位,所以对于负数的位数是stringSize(-i) + 1

5.3 valueOf

valueOf是自动拆箱的核心,解读看注释。

public static Integer valueOf(int i) {
    /*
    如果传入参数i在IntegerCache范围内,
    就不会实例化一个新的Integer对象,直接返回IntegerCache缓存的对象
    否则new一个新的Integer对象 
     */
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

5.4 intValue

intValue是自动拆箱的核心。

    public int intValue() {
        return value;
    }

5.5 equals和hashcode

equals方法先判断传入参数是否是Integer类型,是的话拆箱,进行比较

   public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

hashcode方法直接返回value

    public static int hashCode(int value) {
        return value;
    }

5.6 compare

compareTo 方法内部直接调用 compare 方法:

    public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }

6. 装箱、拆箱

自动装箱拆箱是JDK1.5之后的语法糖,在编译期,根据代码,在生成class文件的时候进行。

  1. 自动装箱

    自动装箱本质就是调用了valueOf,注意valueOf方法有用到IntegerCache

    对于Integer a = 128;这段代码,经过反编译工具,可以看到class文件的本质就是Integer a = Integer.valueOf(128);

  2. 自动拆箱

    自动拆箱本质就是调用了intValue。如下自动拆箱例子。

    Integer a = new Integer(128);
    int m = a;
    

    经过反编译工具,可以看到class文件的本质就是

    Integer a = new Integer(128);
    int m = a.intValue();
    
  3. 示例

     public static void main(String[] args) throws InterruptedException {
            Integer i = 10;
            Integer j = 10;
            System.out.println(i == j);//true
    
            Integer a = 128;
            Integer b = 128;
            System.out.println(a == b);//false
    
            int k = 10;
            System.out.println(k == i);//true
            int kk = 128;
            System.out.println(kk == a);//true
    
            Integer m = new Integer(10);
            Integer n = new Integer(10);
            System.out.println(m == n);//false
        }
    

    第一次比较 i == jInteger i = 10;进行了自动装箱,调用valueOf方法,又因为这个方法里面会判断传入参数有没有在IntegerCache的范围内,10在这个返回内,所以并不会创建新的对象,j同理,因此ij指向的是同一个对象(IntegerCache中已经有的对象),所以第一次比较结果为true

    第二次比较和第一次同样进行了自动装箱,但因为128超过了IntegerCache的范围,因此会新建一个对象,所以ab指向的是不同的对象,结果为false

    第三次比较k==ik是基本数据类型,这里进行了自动拆箱,也即k==intValue(i),这就是比较两个int值,结果为true,第四次同理

    第五次直接通过new的方式来创建Integer实例,并不会调用自动装箱,也就是没有通过valueOf方法,不会用到IntegerCache的缓存,所有mn指向不同对象,结果为false

    另外,IntegerCache可以通过修改jvm启动参数Djava.lang.Integer.IntegerCache.high,来调解缓存,如果改为256,那么第二次比较的结果也会为true,而仔细看了源码之后发现,最少是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); //这里取设置的启动参数和127的最大值
                        // Maximum array size is Integer.MAX_VALUE
                        h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                    } catch( NumberFormatException nfe) {
                        // If the property cannot be parsed into an int, ignore it.
                    }
                }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值