码迷,mamicode.com
首页 > 编程语言 > 详细

Java Integer类分析

时间:2015-08-29 20:04:24      阅读:275      评论:0      收藏:0      [点我收藏+]

标签:

  public static final int   MIN_VALUE = 0x80000000;  -2^31

 public static final int   MAX_VALUE = 0x7fffffff; 2^31-1

 

 public static String toString(int i, int radix)

该方法返回一个字符串形式的参数,第二个参数为指令的基数,将第一个参数转换为以第二个参数为基数的字符串

package com.yiibai;

import java.lang.*;

public class IntegerDemo {

   public static void main(String[] args) {

     Integer i = new Integer(10);
   
     // returns a string representation of the specified integer with radix 10
     String retval = i.toString(30, 10);
     System.out.println("Value = " + retval);
     
     // returns a string representation of the specified integer with radix 16
     retval = i.toString(30, 16);
     System.out.println("Value = " + retval);
     
     // returns a string representation of the specified integer with radix 8
     retval = i.toString(30, 8);
     System.out.println("Value = " + retval);
   }
} 

 

返回结果:

Value = 30 Value = 1e Value = 36

 

如果基数小于Character.MIN_RADIX或大于Character.MAX_RADIX的,则基数10代替.

这个地方MIN_RADIX不能为1,是因为基数不能为1,如果基数为1,就会进入死循环,1都不管多少次方都不可能成为不是1的其它数值

下面的ASCII字符被用来作为数字: 0123456789abcdefghijklmnopqrstuvwxyz

 

 

将整数转换为16进制

 public static String toHexString(int i) {
        return toUnsignedString(i, 4);
    }

这 个地方解释一下为什么是4,因为16=2^4,操作:先将1向左移动4位即radix = 1 <<4 ,得到二进制10000,然后减去1,得到掩码mask=1111,这个mask就是用来与要转换整数,从低到高位,每四位一次进行&操作,这样 没四位与一次,得到一个16进制数值,直到所有的二进制转换为16进制为止。

 

将整数转换为8进制

 public static String toOctalString(int i) {
        return toUnsignedString(i, 3);
    }

这个地方的3就是因为转换为8进制,8 = 2 ^3,调用与16进制相同的方法。

 

将整数转换为二进制:

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

这个地方的1同上,2 = 2^1,调用方法都是相同的

 

这个地方就是进制转换的时候调用的方法,i就是要进行转换的10进制数,shift就是那个4,3,1

radix就是将1向左移动几位,mask就是得到用来转换用的掩码

  private static String toUnsignedString(int i, int shift) {
        char[] buf = new char[32];
        int charPos = 32;
        int radix = 1 << shift;
        int mask = radix - 1;
        do {
            buf[--charPos] = digits[i & mask];
            i >>>= shift;
        } while (i != 0);

        return new String(buf, charPos, (32 - charPos));
    }

 

这个地方是将一个整数转换为字符串,Integer.MIN_VALUE = 0x80000000

其中getChars是一个比较有趣的方法,将整数转换后放在buf中

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

 

 static void getChars(int i, int index, char[] buf) {
        int q, r;
        int charPos = index;
        char sign = 0;

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

        // Generate two digits per iteration
        while (i >= 65536) {  
            q = i / 100;
        // really: r = i - (q * 100);
            r = i - ((q << 6) + (q << 5) + (q << 2));
            i = q;
            buf [--charPos] = DigitOnes[r];   //求的个位数
            buf [--charPos] = DigitTens[r];     //求的十位数
        }

        // Fall thru to fast mode for smaller numbers
        // assert(i <= 65536, i);
        for (;;) {
            q = (i * 52429) >>> (16+3);                                         //这个地方52429数字非常神奇!!!!!!!!!!!!!!!
            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;
        }
    }

用来计算十位数

 final static char [] DigitTens = {
        ‘0‘, ‘0‘, ‘0‘, ‘0‘, ‘0‘, ‘0‘, ‘0‘, ‘0‘, ‘0‘, ‘0‘,
        ‘1‘, ‘1‘, ‘1‘, ‘1‘, ‘1‘, ‘1‘, ‘1‘, ‘1‘, ‘1‘, ‘1‘,
        ‘2‘, ‘2‘, ‘2‘, ‘2‘, ‘2‘, ‘2‘, ‘2‘, ‘2‘, ‘2‘, ‘2‘,
        ‘3‘, ‘3‘, ‘3‘, ‘3‘, ‘3‘, ‘3‘, ‘3‘, ‘3‘, ‘3‘, ‘3‘,
        ‘4‘, ‘4‘, ‘4‘, ‘4‘, ‘4‘, ‘4‘, ‘4‘, ‘4‘, ‘4‘, ‘4‘,
        ‘5‘, ‘5‘, ‘5‘, ‘5‘, ‘5‘, ‘5‘, ‘5‘, ‘5‘, ‘5‘, ‘5‘,
        ‘6‘, ‘6‘, ‘6‘, ‘6‘, ‘6‘, ‘6‘, ‘6‘, ‘6‘, ‘6‘, ‘6‘,
        ‘7‘, ‘7‘, ‘7‘, ‘7‘, ‘7‘, ‘7‘, ‘7‘, ‘7‘, ‘7‘, ‘7‘,
        ‘8‘, ‘8‘, ‘8‘, ‘8‘, ‘8‘, ‘8‘, ‘8‘, ‘8‘, ‘8‘, ‘8‘,
        ‘9‘, ‘9‘, ‘9‘, ‘9‘, ‘9‘, ‘9‘, ‘9‘, ‘9‘, ‘9‘, ‘9‘,
        } ;

 

用来计算个位数

 final static char [] DigitOnes = {
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘,
        } ;

 

用来计算可以代表的字符

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

 

用来计算这个数是几位的数字

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

 

这个用来判断一个正数,判断这是几位数,正好调用上面的sizeTable

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

 

 

下面这个方法是将一个radix进制的s转换成十进制的整数

比如s为32,radix 为4,那么最后转换成的整数时3*4+2 = 14;

这个地方会因为字符串不满足格式个出现异常,所以首先抛出NUmberFormatException异常

 

/ * @param      s   the {@code String} containing the integer
     *                  representation to be parsed
     * @param      radix   the radix to be used while parsing {@code s}.
     * @return     the integer represented by the string argument in the
     *             specified radix.
     * @exception  NumberFormatException if the {@code String}
     *             does not contain a parsable {@code int}.
     */
    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.
         */

//这个地方当输入为null或者输入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) {

            //这个地方单独出去第一个字符是用来判断这个是否是符号标示,如果是“-”或者“+”,那么他们<‘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);
                //如果是+或者-,但长度是1的话也是不允许的,所以会报错
                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;
    }

 

java.lang.Character.digit(char ch, int radix)API

public static int digit(char ch,
                        int radix)

    • 返回使用指定基数的字符 ch 的数值。

      如果基数不在 MIN_RADIX <= radix <= MAX_RADIX 范围之内,或者 ch 的值是一个使用指定基数的无效数字,则返回 -1。如果以下条件中至少有一个为真,则字符是一个有效数字:

      • 方法 isDigittrue,且字符(或分解的单字符)的 Unicode 十进制数值小于指定的基数。在这种情况下,返回十进制数值。        

      • 字符为 ‘A‘‘Z‘ 范围内的大写拉丁字母之一,且它的代码小于 radix + ‘A‘ - 10。在这种情况下,返回 ch - ‘A‘ + 10。        

      • 字符为 ‘a‘‘z‘ 范围内的小写拉丁字母之一,且它的代码小于 radix + ‘a‘ - 10。在这种情况下,返回 ch - ‘a‘ + 10

           

这个地方从返回就可以看出来 parseInt(String s)实际上是parseInt(String s, int radix)的特出情况,及radix为10的时候

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

 public static Integer valueOf(String s) throws NumberFormatException {
        return Integer.valueOf(parseInt(s, 10));
    }

这 个地方可以清楚的看到value(String s ,int radix)先返回valueof(int i),而valueof(int i)又调用了parseInt(String s,int radix)所以本质上还是执行了parseInt(String s,int radix)

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

 

IntegerCache是Integer的内部类,用来将-128——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;//h值,可以通过设置jdk的AutoBoxCacheMax参数调整(以下有解释),自动缓存区间设置为[-128,N]。注意区间的下界是固定 
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);// 取较大的作为上界,但又不能大于Integer的边界MAX_VALUE
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low));
            }
            high = h;

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

        private IntegerCache() {}
    }

 

 

这个方法就是用来调用上面缓存里面的对象,如果整数值在缓存对象数组范围内,就直接返回缓存对象,如果不在里面,就要为其新建对象

Integer i= 5;这是自动装箱问题,java运行的就是下面这段代码

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

 

构造方法,默认执行是parse(Stirng s, int 10)方法。

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

 

//比较两个整数是否相等,首先判断被比较对象是否是整型实例,如果是,将其转换成int类型进行比较

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

 

//

public static Integer getInteger(String nm, Integer val)返回具有指定名称的系统属性的整数值。

第一个参数被视为系统属性的名称。通过 System.getProperty(java.lang.String) 方法可以访问系统属性。然后,根据每个 Integer.decode 方法,将该属性的字符串值解释为一个整数值,并返回一个表示该值的 Integer 对象。 如果属性值以两个 ASCII 字符 0x 或者 ASCII 字符 # 开始,并且后面没有减号,则将它的剩余部分解析为十六进制整数,就好像以 16 为基数调用 valueOf(java.lang.String, int) 方法一样。

 

如果属性值以 ASCII 字符 0 开始,后面还有其他字符,则将它解析为八进制整数,就好像以 8 为基数调用 valueOf(java.lang.String, int) 方法一样。

 

否则,将属性值解析为十进制整数,就好像以 10 为基数调用 valueOf(java.lang.String, int) 方法一样。

 

第二个参数是默认值。如果未具有指定名称的属性,或者属性的数字格式不正确,或者指定名称为空或 null,则返回默认值。

 

 public static Integer getInteger(String nm, Integer val) {
        String v = null;
        try {
            v = System.getProperty(nm);//这个方法的解析放到System类中
        } catch (IllegalArgumentException e) {
        } catch (NullPointerException e) {
        }
        if (v != null) {
            try {
                return Integer.decode(v); //这个方法在下面进行具体介绍
            } catch (NumberFormatException e) {
            }
        }
        return val;
    }

 

//这个方法是调用上面的方法,并且是使第二个参数的默认值为null

 public static Integer getInteger(String nm) {
        return getInteger(nm, null);
    }

 

 

//这个地方实际上是先调用的最上面的方法,同样也是使第二个参数为null,然后根据返回结果,如果是null,将第二个参数转换成Integer类型返回

 public static Integer getInteger(String nm, int val) {
        Integer result = getInteger(nm, null);
        return (result == null) ? Integer.valueOf(val) : result;
    }

 

//这个方法是方法解码字符串转换为整数,(1)判断长度如果是0,则抛出0长度异常,(2)判断其第一个字符是‘-‘还是‘+‘,

(3)调用String.startWith(String s,int i)方法,判断这是多少进制的数值(4)如果第二个字符又出现了‘-‘或是‘+‘,则抛出符号位置异常

(5)调用Integer.valueof(String s, int i)方法,将其解码为十进制整数(6)根据其正负值,返回相应的数值

(7)最后抛出的异常是如果转换的整数刚好是Integer.MIN_VALUE,因为正数不包含,所以抛出异常,需要在异常中获取返回

public static Integer decode(String nm) throws NumberFormatException {
        int radix = 10;
        int index = 0;
        boolean negative = false;
        Integer result;

        if (nm.length() == 0)
            throw new NumberFormatException("Zero length string");
        char firstChar = nm.charAt(0);
        // Handle sign, if present
        if (firstChar == ‘-‘) {
            negative = true;
            index++;
        } else if (firstChar == ‘+‘)
            index++;

        // Handle radix specifier, if present
        if (nm.startsWith("0x", index) || nm.startsWith("0X", index)) {
            index += 2;
            radix = 16;
        }
        else if (nm.startsWith("#", index)) {
            index ++;
            radix = 16;
        }
        else if (nm.startsWith("0", index) && nm.length() > 1 + index) {
            index ++;
            radix = 8;
        }

        if (nm.startsWith("-", index) || nm.startsWith("+", index))
            throw new NumberFormatException("Sign character in wrong position");

        try {
            result = Integer.valueOf(nm.substring(index), radix);
            result = negative ? Integer.valueOf(-result.intValue()) : result;
        } catch (NumberFormatException e) {
            // If number is Integer.MIN_VALUE, we‘ll end up here. The next line
            // handles this case, and causes any genuine format error to be
            // rethrown.
            String constant = negative ? ("-" + nm.substring(index))
                                       : nm.substring(index);
            result = Integer.valueOf(constant, radix);
        }
        return result;
    }

 

//比较两个整数,如果小于返回-1,相等返回0,大于返回1

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

 

//实际上是调用的compare方法

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

 

1.第一步的作用是把最高位1右移移位,并与原数据按位取或。那么这就使得最高位和它的下一位是连续两个1。

2、第二步的作用是把刚刚移位得到连续两个1继续右移两位并与原数据按位取或。那么这就使得最高两位和它的下两个连续位组成四个连续的1。

3、 以此类推,最终得到的i是从开始的最高位到结束全是1。并减去i不带符号的右移一位,即可得到一个int数据的最高位的值。

4、上述情况是针对于i不为零和负数的情况,如果i为零,那么得到的结果始终为零。如果i位负数,那么得到的结果始终是-2147483648。即等于Integer.MIN_VALUE。(原因在于负数的最高位始终为1,即是负数的符号位)

 public static int highestOneBit(int i) {
        // HD, Figure 3-1
        i |= (i >>  1);
        i |= (i >>  2);
        i |= (i >>  4);
        i |= (i >>  8);
        i |= (i >> 16);
        return i - (i >>> 1);
    }

 

//求最低位数值,用这个数字与他的负数进行相与操作,用补码进行相与操作
 public static int lowestOneBit(int i) {
        // HD, Section 2-1
        return i & -i;
    }

 

//求得从高位开始到第一个非零数值之间0的个数

具体做法:

(1)如果是0,则返回32

(2)无符号右移16为,如果为0,说明左边这16位都为0,左移16位,将最左边的16删除

(3)无符号右移24位,如果是0,说明左边的8位都为0,左移8位,将左边的8位删除掉

(4)无符号右移28位,如果是0,说明左边的4位都为0,左移4位,将左边的4位删除掉

(5)无符号右移30位,如果是0,说明左边的2位都为0,左移2位,将左边的2位删除掉

(6)无符号右移31位,如果是0,说明原始数从小到大第二位是0,如果不是,说明是1,将一开始初始化的1减掉

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的总数为n =  31

(2)左移16为,如果结果不为0,说明右边这16位存在不为0的值,保存移动之后的结果,接下来继续对其进行移位操作,n = n - 16

(3)左移8位,如果结果不为0,说明右边的8位存在不为0的值,保存移动之后的结果,接下来继续对其进行移位操作,n = n - 8

(4)左移4位,如果结果不为0,说明右边的4位存在不为0的值,保存移动之后的结果,接下来继续对其进行移位操作,n = n - 4

(5)左移2位,如果结果不为0,说明右边的2位存在不为0的值,保存移动之后的结果,接下来继续对其进行移位操作,n = n - 2

(6)经过上一步结果不为0,说明了最后两位有三种可能,要么其中一位为1,另外一位为0;要么都为1;在这里这用考虑第一种情况就行,

先左移1位,得到最低位的数值,然后无符号右移31位,这样就能将最低位回复到正常位置

(7)最后用n减去这个数值,如果这个数值为1,减去之后结果为0,正好返回0;如果这个数值为0,减去结果为1,

 

public static int numberOfTrailingZeros(int i) {
        // HD, Figure 5-14
        int y;
        if (i == 0) return 32;
        int n = 31;
        y = i <<16; if (y != 0) { n = n -16; i = y; }
        y = i << 8; if (y != 0) { n = n - 8; i = y; }
        y = i << 4; if (y != 0) { n = n - 4; i = y; }
        y = i << 2; if (y != 0) { n = n - 2; i = y; }
        return n - ((i << 1) >>> 31);
    }

 

//这是求解一个整数转换成二进制补码之后,其中1的个数

 

二分法,两两一组相加,之后四个四个一组相加,接着八个八个,最后就得到各位之和了。

第一行是计算每两位中的 1 的个数,并且用该对应的两位来存储这个个数,
如: 01101100 -> 01011000 ,即先把前者每两位分段 01 10 11 00 ,分别有 1 1 2 0 个1,用两位二进制数表示为 01 01 10 00, 合起来为 01011000.

第二行是计算每四位中的 1 的个数,并且用该对应的四位来存储这个个数.
如: 01101100 经过第一行计算后得 01011000 ,然后把 01011000 每四位分段成 0101 1000 ,段内移位相加: 前段 01+01 =10 , 后段 10+00=10, 分别用四位二进制数表示为 0010 0010, 合起来为 00100010 .
下面的各行以此类推,分别计算每8位,16位,32位中的 1 的个数.
将 0x55555555, 0x33333333, 0x0f0f0f0f 写成二进制数的形式就容易明白了.

这个还有个浅显的理解方式:

(1) 假设转换之后的二进制整数的最后两位是XY,那么无符号右移一位,然后与0101相与之后得到的0X,用原始数据相减之后得到二进制数X(Y-X)(转换 成十进制之后:X+Y,即:两位一组表示1的个数),得到的结果是每两位一组中1的个数,只不过 还是用二进制表示的

(2)将(1)中的到 的结果,每四位一组,先与0011相与,求得后两位中1的个数,然后加上结果无符号右移两位与0011相与,得到前两位中1 的个数,例子:XYZM(表示的是二进制最后四位),因为(1)中的结果都是两位一组来计算的,所以与0011相与后得到ZM,然后右移之后再相与得到 XY,这样相加的结果就是1的个数(2*X+Y+2*Z+M),最后的结果仍用二进制表示,就将(1)中的两位一组表示变成了四位一组表示

(3) 这一步先右移四位,然后与原数相加,最后与00001111进行相与操作。实际上就上将两个四位进行求和,然后与1111相与,但是相加的时候都会有两次 重复,所以将其中一次与0000相与。举个例子,0101001100110011,右移之后的数据0000010100110011,因为第二组中 0101+0011,然后与1111相与,所以第一组四位0101与0000相与,这样就避免了重复相加

(4)将上一步的结果右移8位,然后与之相加,这个地方记住只看第二组跟第四组的结果,因为这两个刚好是原来第一组与第二组的和,第三组与第四组的和

(5)将上一步的结果右移16位,然后相加,这里只看第二组的最后八位结果,这就是叠加之后的和,其他位都不用看

(6)最有一步与0x3f相与,因为32位最多只需要5位,这里可以多一位,得到最后的结果

  public static int bitCount(int i) {
        // HD, Figure 5-2
        i = i - ((i >>> 1) & 0x55555555);
        i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
        i = (i + (i >>> 4)) & 0x0f0f0f0f; 
        i = i + (i >>> 8);                      //16位一组统计 结果放在 后8位        i = i + (i >>> 16);
        return i & 0x3f;                        // 32位1组统计 结果放在 后16位   

 

//这个地方我用了比较长时间来研究

这个方法的主要作用就是要将i转换成二进制之后,然后将数值先向左移动distance个单位,然后将数值再无符号向右移动【distance的补码后五位的值计算出来的数值(因为int只有32位,所以只有后五位的数值才是有效数字)】的单位,最后将两个结果取或操作。

举个例子,假设i转换成二进制之后为AB【A:32-distance位数字,B:distance位数字】,经过下面方法之后变成了BA,BA就是所求得的结果

public static int rotateLeft(int i, int distance) {
        return (i << distance) | (i >>> -distance);
    }

 

下面这个方法正好与上面相反

public static int rotateRight(int i, int distance) {
        return (i >>> distance) | (i << -distance);
    }

 

这个方法是将所有的位数进行翻转操作,即:0与31互换,1与30互换,。。。。。

具体操作:

(1)两位一组,进行互换位置

(2)四位一组,1与3,2与4互换位置

(3)八位一组,1与8,2与7,3与6,4与5互换位置

(4)现在的结果是四个八位数组,将第四个数组移动到第一个位置,将第三个数组移动到第二个位置,将第二个数组移动到第三个位置,第一个数组移动到第四个位置

public static int reverse(int i) {
        // HD, Figure 7-1
        i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
        i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
        i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
        i = (i << 24) | ((i & 0xff00) << 8) |
            ((i >>> 8) & 0xff00) | (i >>> 24);
        return i;
    }

 

//返回int值的正负号

具体操作先将原始数据转换成二进制补码,然后右移31,再将原始数据取负,转换成二进制补码,右移31位,最后进行或操作

正数返回1,负数返回-1,0返回0

如果是正数i>>31 的结果是0000。。。。0000,-i>>>31的结果是0000。。。。0001,最后结果就是1

如果是负数i>>31的结果是1111。。。。1111,-1>>>31的结果是0000。。。。0000,最后的结果是-1

public static int signum(int i) {
        // HD, Section 2-7
        return (i >> 31) | (-i >>> 31);
    }

 

这个地方是以Byte为单位进行互换位置

将int转换成二进制补码,然后八位一组,分成四组,第一组跟第四组互换位置,二三组互换位置

 public static int reverseBytes(int i) {
        return ((i >>> 24)           ) |
               ((i >>   8) &   0xFF00) |
               ((i <<   8) & 0xFF0000) |
               ((i << 24));
    }

 

Java Integer类分析

标签:

原文地址:http://www.cnblogs.com/wzyxidian/p/4769573.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!