请回答下这两个Integer相等不

第一组

Integer a=127;

Integer b=127;

System.out.println(a==b);

第二组

Integer a=128;

Integer b=128;


System.out.println(a==b);

答案是第一组输出true,第二组输出false。

补充下,为什么?

首先debug这行代码: Integer a=1;

它会进入Integer.valueOf(int n)这个方法,这个与普通的java类的初始化方法是不一样的。下面的源码这有个方法的实现。

看下Integer类的源码:

/**
 * 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.
   缓存-128到127的数字,这个缓存在第一阶段初始化(这里说的是Jvm初始化,所以我们debug断点是打不到的)。
可以使用jvm参数(-XX:AutoBoxCacheMax=<size>)控制缓存大小,初始化参数java.lang.Integer.IntegerCache.high。
 */

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() {}
}

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

从上面源码可以看出:

1.这个问题来源于,Integer有个IntegerCache,取值时(ValueOf)会先从这个cache取。

2.cache范围,可以设置-XX:AutoBoxCacheMax=来提高cache的上限。下限是-128,不可扩。



Java中的Integer占4个字节,每个字节8位,那么就是32位。

而第一位是符号位正数为0,负数为1,我们可以用下面这两句代码验证下:

System.out.println(Integer.toBinaryString(Integer.MAX_VALUE)+":"+Integer.MAX_VALUE);
System.out.println(Integer.toBinaryString(Integer.MIN_VALUE)+":"+Integer.MIN_VALUE);
输出:

1111111111111111111111111111111:2147483647
10000000000000000000000000000000:-2147483648
可以看出Integer.MAX_VALUE的二进制形式比Integer.MIN_VALUE少一位,因为它第一位是0,未显示出来。

这里补充一下补码的知识:在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。

正整数的补码是其二进制表示,与原码相同。
求负整数的补码,将其原码除符号位外的所有位取反(0变1,1变0,符号位为1不变)后加1。

上面的输出二进制就是补码,与上面的正负数补码定义,相互印证。


即然二进制是31(32-1)位,那么最大数应该是(2的31次方-1)。用代码验证下:

System.out.println(Integer.MAX_VALUE+":"+(Double.valueOf(Math.pow(2, 31)).longValue()-1));
输出:

2147483647:2147483647
说明这个计算没有问题。

loga(b),用Java怎么算,用换底公式。 loga(b)=loge(b)/loge(a)。即Math.log(b)/Math.log(a)

看一下Integer的二进制方法源码:

public static String toBinaryString(int i) {
    return toUnsignedString0(i, 1);
}

/**
 * Convert the integer to an unsigned number.
 */
private static String toUnsignedString0(int val, int shift) {
    // assert shift > 0 && shift <=5 : "Illegal shift value";
    int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
    int chars = Math.max(((mag + (shift - 1)) / shift), 1);
    if (COMPACT_STRINGS) {
        byte[] buf = new byte[chars];
        formatUnsignedInt(val, shift, buf, 0, chars);
        return new String(buf, LATIN1);
    } else {
        byte[] buf = new byte[chars * 2];
        formatUnsignedIntUTF16(val, shift, buf, 0, chars);
        return new String(buf, UTF16);
    }
}


static void formatUnsignedInt(int val, int shift, byte[] buf, int offset, int len) {
    int charPos = offset + len;
    int radix = 1 << shift;
    int mask = radix - 1;
    do {
        buf[--charPos] = (byte)Integer.digits[val & mask];
        val >>>= shift;
    } while (charPos > offset);
}


/**
 * All possible chars for representing a number as a String
 */
static final 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 i the value whose number of leading zeros is to be computed
 * @return the number of zero bits preceding the highest-order
 *     ("leftmost") one-bit in the two's complement binary representation
 *     of the specified {@code int} value, or 32 if the value
 *     is equal to zero.
 * @since 1.5
 */
@HotSpotIntrinsicCandidate
public static int numberOfLeadingZeros(int i) {
    // HD, Figure 5-6
    if (i == 0)
        return 32;
    int n = 1;
    if (i >>> 16 == 0) { n += 16; i <<= 16; }
    if (i >>> 24 == 0) { n +=  8; i <<=  8; }
    if (i >>> 28 == 0) { n +=  4; i <<=  4; }
    if (i >>> 30 == 0) { n +=  2; i <<=  2; }
    n -= i >>> 31;
    return n;
}
返回最左边的0的个数。这些0有两部分,第1位是补码(符号位)。如果是0返回32位。
传入参数即可以是正数,也可以是负数。如果是正数则符号位是0,算是一个0.如果是负数则符号位是1,那么返回一定是0.以3为例,3的2进制形式是:
00000000000000000000000000000011

mybatis中的一个应用:

@MapKey("gradeId")
    Map queryAnswerRecord(@Param("recordId")Long recordId);

这个gradeId本来是个Integer,这儿却要写成String。因为如果是Integer,在返回后直接取map.get(3),这样的会取不到。

文/程忠 浏览次数:0次   2018-12-06 19:19:19

相关阅读

微信扫描-捐赠支持
加入QQ群-技术交流

评论:
点击刷新

↓ 广告开始-头部带绿为生活 ↓
↑ 广告结束-尾部支持多点击 ↑