Integer源码阅读

简介: Integer源码阅读

对于java自动装箱与自动拆箱我目前只停留在知道使用的层面上,为了能够进一步的对其进行深入的研究,下面从源码开始对其进行分析。


分析类


最首先的当然是从类的继承实现情况开始。


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


对与这个Integer类,它实现了Comparable接口,继承了Number.


Comparatable : 强行对实现它的类的每个实例进行自然排序,该接口的唯一方法compareTo方法被称为自然比较方法

Number类:继承了Serializable接口,内有实现对数操作的一些方法。

该类被final修饰,不可被继承

public关键字修饰,这个很好理解,这个类定义出来是被所有的类的使用的,包括Java的使用者定义的类来使用的。所以一定是public的。


分析属性


/**
 * The value of the {@code Integer}.
 *
 * @serial
 */
private final int value;


  • Integer用于存储数据的属性,类型为整形


常量分析


//A constant holding the minimum value an int can have, -231.
@Native public static final int   MIN_VALUE = 0x80000000;
//A constant holding the maximum value an int can have, 231-1.
@Native public static final int   MAX_VALUE = 0x7fffffff;


  1. 这两个属性都是一个整形变量,用来保存最大值与最小值
  2. 注解修饰成员变量,表示这个变量可以被本地代码引用
  3. final修饰 不可被修改


public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");


  • 获取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'
};


  • 数字为字符串类型的所有可能表现形式


方法分析


public static String toString(int i, int radix) {
    if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
        radix = 10;
     /* 如果是10进制,直接转字符串即可 */
    /* Use the faster version */
    if (radix == 10) {
        return toString(i);
    }
    // 存放转换进制后的字符数组
    char buf[] = new char[33];
    boolean negative = (i < 0);
    // 将指针指向buf数组最后一位,以便后边存放字符
    int charPos = 32;
    if (!negative) {
        i = -i;
    }
    /* 使用短除法来转换进制 */
    while (i <= -radix) {
        buf[charPos--] = digits[-(i % radix)];
        i = i / radix;
    }
    buf[charPos] = digits[-i];
    if (negative) {
        buf[--charPos] = '-';
    }
    return new String(buf, charPos, (33 - charPos));
}


  • 返回由第二个参数指定的基数中的第一个参数的字符串表示形式,例如:Integer.toString(3,2),得到3的二进制表示形式。
public static String toUnsignedString(int i, int radix) {
    return Long.toUnsignedString(toUnsignedLong(i), 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);
}


  • 返回一个代表指定整形类型的String类型对象


public static String toUnsignedString(int i) {
    return Long.toString(toUnsignedLong(i));
}



将参数的字符串表示形式返回为无符号十进制值。


接下来,是这个封装类的最==重要==的几个方法:


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) {
            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') { // Possible leading "+" or "-"
                if (firstChar == '-') {
                    negative = true;
                    limit = Integer.MIN_VALUE;
                } else if (firstChar != '+')
                    throw NumberFormatException.forInputString(s);
                if (len == 1) // Cannot have lone "+" or "-"
                    throw NumberFormatException.forInputString(s);
                i++;
            }
            multmin = limit / radix;
            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;
    }
例子:
       parseInt("0", 10) returns 0
       parseInt("473", 10) returns 473
       parseInt("+42", 10) returns 42
       parseInt("-0", 10) returns 0
       parseInt("-FF", 16) returns -255
       parseInt("1100110", 2) returns 102
       parseInt("2147483647", 10) returns 2147483647
       parseInt("-2147483648", 10) returns -2147483648
       parseInt("2147483648", 10) throws a NumberFormatException
       parseInt("99", 8) throws a NumberFormatException
       parseInt("Kona", 10) throws a NumberFormatException
       parseInt("Kona", 27) returns 411787


  • 将字符串参数解析为第二个参数指定的基数中的有符号整数。


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


  • 这个方法一看方法体就知道了,不用多说


public static int parseUnsignedInt(String s, int radix)
            throws NumberFormatException {
    if (s == null)  {
        throw new NumberFormatException("null");
    }
    int len = s.length();
    if (len > 0) {
        char firstChar = s.charAt(0);
        if (firstChar == '-') {
            throw new
                NumberFormatException(String.format("Illegal leading minus sign " +
                                                   "on unsigned string %s.", s));
        } else {
            if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
                (radix == 10 && len <= 9) ) { // Integer.MAX_VALUE in base 10 is 10 digits
                return parseInt(s, radix);
            } else {
                long ell = Long.parseLong(s, radix);
                if ((ell & 0xffff_ffff_0000_0000L) == 0) {
                    return (int) ell;
                } else {
                    throw new
                        NumberFormatException(String.format("String value %s exceeds " +
                                                           "range of unsigned int.", s));
                }
            }
        }
    } else {
        throw NumberFormatException.forInputString(s);
    }
}


  • 将字符串参数解析为第二个参数指定的基数中的无符号整数。
    public static int parseUnsignedInt(String s) throws NumberFormatException {
        return parseUnsignedInt(s, 10);
    }


  • 不多说,看方法体
    public static Integer valueOf(String s, int radix) throws NumberFormatException {
        return Integer.valueOf(parseInt(s,radix));
    }


  • 返回一个 Integer指定的 int值的 Integer实例。
public static Integer valueOf(String s) throws NumberFormatException {
    return Integer.valueOf(parseInt(s, 10));
}


  • 看方法体
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}


  • 返回一个 Integer指定的 int值的 Integer实例
  • 这个方法需要特别注意:IntegerCache为Integer类的缓存类,默认缓存了-128~127的Integer值,如遇到[-128,127]范围的值需要转换为Integer时会直接从IntegerCache中获取


/**
 * Constructs a newly allocated {@code Integer} object that
 * represents the specified {@code int} value.
 *
 * @param   value   the value to be represented by the
 *                  {@code Integer} object.
 */
public Integer(int value) {
    this.value = value;



  • 构造方法


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


构造一个新分配的Integer对象,该对象表示由String参数表示的int值。字符串转换为int值的方式与parseInt方法用于基数10的方式完全相同。


public String toString() {
    return toString(value);
}


  • 重写Object类的toString()方法
@Override
public int hashCode() {
    return Integer.hashCode(value);
}
public static int hashCode(int value) {
    return value;
}


  • 重写hashCode()方法
public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}


  • 重写equals()方法
/**
 * Compares two {@code Integer} objects numerically.
 *
 * @param   anotherInteger   the {@code Integer} to be compared.
 * @return  the value {@code 0} if this {@code Integer} is
 *          equal to the argument {@code Integer}; a value less than
 *          {@code 0} if this {@code Integer} is numerically less
 *          than the argument {@code Integer}; and a value greater
 *          than {@code 0} if this {@code Integer} is numerically
 *           greater than the argument {@code Integer} (signed
 *           comparison).
 * @since   1.2
 */
public int compareTo(Integer anotherInteger) {
    return compare(this.value, anotherInteger.value);
}
/**
 * Compares two {@code int} values numerically.
 * The value returned is identical to what would be returned by:
 * <pre>
 *    Integer.valueOf(x).compareTo(Integer.valueOf(y))
 * </pre>
 *
 * @param  x the first {@code int} to compare
 * @param  y the second {@code int} to compare
 * @return the value {@code 0} if {@code x == y};
 *         a value less than {@code 0} if {@code x < y}; and
 *         a value greater than {@code 0} if {@code x > y}
 * @since 1.7
 */
public static int compare(int x, int y) {
    return (x < y) ? -1 : ((x == y) ? 0 : 1);
}


  • 实现接口方法
 /**
     * 返回指定int值的符号函数(所谓的符号函数就是确定输入值的符号【正数|负数|0】)
     * 如果指定值为负数,则返回值为-1;如果指定值为0,则返回值为0;如果指定值为正数,则返回值为1
     *
     * @param i 要计算其符号的值
     * @return 返回指定int值的符号,如果是负数返回-1,0返回0,正数返回1
     */
    public static int signum(int i) {
        // 如果是正数,则可以通过(-i >>> 31)确定符号,即获取最高位的符号。因为(i >> 31)会为0。
        // 如果是负数,则可以通过(i >> 31)确定符号,即获取最高位的符号。因为(-i >>> 31)会为0。
        return (i >> 31) | (-i >>> 31);
    }


  • 返回指定int值的符号函数
  • 分析:
/*
(i >> 31) | (-i >>> 31)
第一种情况:i是正数,则返回1。例如i=96所对应的二进制是0000 0000 0000 0000 0000 0000 0110 0000
        i=0000 0000 0000 0000 0000 0000 0110 0000
    i>>31=0000 0000 0000 0000 0000 0000 0000 0000
       -i=1111 1111 1111 1111 1111 1111 1010 0000
  -i>>>31=0000 0000 0000 0000 0000 0000 0000 0001
(i >> 31) | (-i >>> 31)
          0000 0000 0000 0000 0000 0000 0000 0000
         |
          0000 0000 0000 0000 0000 0000 0000 0001
         =0000 0000 0000 0000 0000 0000 0000 0001
第二种情况:i是0,则返回0。
第三种情况:i是负数,则返回-1。例如i=-96所对应的二进制是1111 1111 1111 1111 1111 1111 1010 0000
        i=1111 1111 1111 1111 1111 1111 1010 0000
    i>>31=1111 1111 1111 1111 1111 1111 1111 1111
       -i=0000 0000 0000 0000 0000 0000 0110 0000
  -i>>>31=0000 0000 0000 0000 0000 0000 0000 0000
(i >> 31) | (-i >>> 31)
          1111 1111 1111 1111 1111 1111 1111 1111
         |
          0000 0000 0000 0000 0000 0000 0000 0000
         =1111 1111 1111 1111 1111 1111 1111 1111
 */


public static int sum(int a, int b) {
    return a + b;
}


  • 返回两数之和
public static int max(int a, int b) {
    return Math.max(a, b);
}


  • 返回最大值


public static int min(int a, int b) {
    return Math.min(a, b);
}



  • 返回最小值


IntegerCache类


/**
 * Cache to support the object identity semantics of autoboxing for values between
 * -128 and 127 (inclusive) as required by JLS.
 *
 * The cache is initialized on first usage.  The size of the cache
 * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
 * During VM initialization, java.lang.Integer.IntegerCache.high property
 * may be set and saved in the private system properties in the
 * sun.misc.VM class.
 */
private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];
    static {
        // high value may be configured by property
        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);
                // 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.
            }
        }
        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;
    }
    private IntegerCache() {}
}



面试:


/**
 * Integer的值在-128到127时(包括-128和127),Integer对象是在IntegerCache.cache产生,会复用已有对象,
 * 也就是说,这个区间的Integer可以直接用等号进行判断。
 * Integer的值在-128到127之外时,Integer对象在堆上产生,不会复用已有对象,用等号会返回false。
 * 建议老老实实用equals()方法来比较Integer对象。
 * @param value
 */


案例1:


        Integer a = 127;
        Integer b = 127;
        Integer c = 128;
        Integer d = 128;
        System.out.println(a==b);
        System.out.println(c==d);
        Integer e = -128;
        Integer f = -128;
        Integer g = -129;
        Integer h = -129;
        System.out.println(e==f);
        System.out.println(g==h);



输出:


true
false
true
false


案例2:


public class EqualsMethod
{
    public static void main(String[] args)
    {
        Integer n1 = new Integer(47);
        Integer n2 = new Integer(47);
        System.out.print(n1 == n2);
        System.out.print(",");
        System.out.println(n1 != n2);
    }
}
选择以上程序段的输出结果为:
A:false,false
B:false,true
C:true,false
D:true,true


选择B,这里直接是new出来的对象不涉及缓存,n1,n2是不同的对象。


结论:


Integer的值在-128到127时,Integer对象是在IntegerCache.cache产生,会复用已有对象,也就是说,这个区间的Integer可以直接用等号进行判断。

Integer的值在-128到127之外时,Integer对象在堆上产生,不会复用已有对象,用等号会返回false


相关文章
|
19天前
|
Java
Integer类【JDK源码分析】
Integer类【JDK源码分析】
25 0
|
19天前
|
缓存
【面试知识点】关于Integer和Int的比较
【面试知识点】关于Integer和Int的比较
|
8月前
|
Java
【面试题精讲】Object类的常见方法有哪些?
【面试题精讲】Object类的常见方法有哪些?
|
6月前
|
存储
String你知道多少细节(含面试题)
String你知道多少细节(含面试题)
27 0
|
10月前
|
Java
踩坑-判断Integer相等
踩坑-判断Integer相等
|
11月前
|
存储 安全 Java
高频面试题-JDK集合源码篇(String,ArrayList)
都是List的子集合,LinkedList继承与Dqueue双端队列,看名字就能看出来前者是基于数组实现,底层采用Object[]存储元素,数组中的元素要求内存分配连续,可以使用索引进行访问,它的优势是随机访问快,但是由于要保证内存的连续性,如果删除了元素,或者从中间位置增加了元素,会设计到元素移位的操作,所以增删比较慢。
59 0
|
Java 数据库连接
Java 最常见的面试题:在 hibernate 中使用 Integer 和 int 做映射有什么区别?
Java 最常见的面试题:在 hibernate 中使用 Integer 和 int 做映射有什么区别?
|
安全 Java 索引
Java String 类,超详细整理,适合新手入门
Java String 类,超详细整理,适合新手入门
156 0
|
Java
java学习第九天笔记-方法175-string概述
java学习第九天笔记-方法175-string概述
69 0
java学习第九天笔记-方法175-string概述
|
缓存 Java 编译器
【JDK源码】String源码学习笔记
【JDK源码】String源码学习笔记
117 0