java.lang.Integer 소스 읽기 (1)

12832 단어
공유하기가 쉽지 않습니다. 좋아요, 지지, 감사합니다.
JDK 소스 요약 정보
클래스 선언
public final class Integer extends Number implements Comparable {}

public abstract class Number implements java.io.Serializable {}
  • 추상류 Number는 BigDecimal, BigInteger, Byte, Double, Float, Integer, Long과 Short류의 초류이다.
  • Number의 하위 클래스는 표시된 수치를byte,double,float,int,long,short로 바꾸는 방법을 제공해야 합니다.
  • Integer에 대응하는 방법은 유형 변환이다. int를byte,double,float,long,short 유형으로 변환한다.

  • compareTo
    Comparable가 구현되었습니다. 대응 방법을 살펴보십시오.
    public int compareTo(Integer anotherInteger) {
        return compare(this.value, anotherInteger.value);
    }
    
    /**
     * jdk1.7         static  ,                
     */
    public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }
    

    toString(int)
    굉장히 많이 쓰는 Tostring 방법을 보겠습니다.
    public static String toString(int i) {
        //    Integer    ,       "-2147483648"
        if (i == Integer.MIN_VALUE)
            return "-2147483648";
        //     i   ,    ,size       1,      (-)
        int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
        //                
        char[] buf = new char[size];
        //       
        getChars(i, size, buf);
        return new String(buf, true);
    }
    

    먼저stringSize 방법을 보십시오. 이 방법은 형삼 i의 위치를 되돌려줍니다.
    final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE };
    
    //     x   
    static int stringSize(int x) {
        //     sizeTable  ,  i    x (i+1)     
        for (int i=0; ; i++)
            if (x <= sizeTable[i])
                return i+1;
    }
    

    다시 getChars 방법을 보면 이 방법은 i를 형성하는 모든 숫자를 buf 수조에 채우는 것이다.getChars라는 방법을 보기 전에 형삼 i의 각 위치의 숫자를 어떻게 얻을 수 있는지 생각해 볼 수 있다.사실은 순환이다. ① 매번 10으로 나눈 나머지 (%)는 개위의 숫자를 얻는다.② 그 다음에 형삼 i를 10으로 나누면 정수로 나누면 끝수(즉 앞의 여수)는 버려진다.③ ①②형삼 i가 0이 될 때까지 반복한다.예를 들어 12, 첫 번째 순환: 10을 제외하고 2를 얻으면 한 자릿수의 숫자가 2이다. 그리고 10을 나누면 1을 얻고 한 자릿수의 2는 버려진다. 두 번째 순환: 10을 제외하고 1을 얻고 10을 나누면 0을 얻는다. 그래서 각각 2와 1을 얻고 순환이 끝난다.코드로 보면 다음과 같습니다.
    while (true) {
        r = i % 10;
        i /= 10;
        //    ↓
        //  n   , r   buf    n  
        if (i == 0) break;
    

    이상은 양수의 상황만 고려했고 음수의 경우 재순환이 끝난 후 buf의 0번째 위치에'-'를 추가하면 된다. 전체 코드는 다음과 같다.
    static void myGetChars(int i, int index, char[] buf) {
        int charPos = index;//     buf        
        char sign = 0;//         
        if (i < 0) {
            sign = '-';
            i = -i;//       
        }        
        while (true) {
            int r = i % 10;
            i /= 10;
            buf [--charPos] = digits [r];//    r    'r',     buf      
            if (i == 0) break;
        }
        if (sign != 0) {
            buf [--charPos] = sign;
        }
    }
    

    보아하니 getChars의 기능을 실현한 것 같은데, jdk에서는 이렇게 하지 않나요?정답: no!원본 보기:
    static void getChars(int i, int index, char[] buf) {
        int q, r;// r   ,        buf  
        int charPos = index;// buf     
        char sign = 0;
    
        if (i < 0) {
            sign = '-';
            i = -i;
        }
    
        // i >= 65536 
        //      buf  2   , i     ,           
        while (i >= 65536) {
            q = i / 100;
            // really: r = i - (q * 100);
            //     r = i - (q * 100)
            // q << 6 = 2^6 = 64
            // q << 5 = 2^5 = 32
            // q << 2 = 2^2 = 4
            // i - q * 100    r  i   2  ,   i%100,             ,    ,             
            r = i - ((q << 6) + (q << 5) + (q << 2));
            i = q;
            //   r    
            buf [--charPos] = DigitOnes[r];
            //   r    
            buf [--charPos] = DigitTens[r];
        }
    
        // Fall thru to fast mode for smaller numbers
        // assert(i <= 65536, i);
        for (;;) {
            //       i/10,
            q = (i * 52429) >>> (16+3);
            r = i - ((q << 3) + (q << 1));  //      r = i-(q*10)
            buf [--charPos] = digits [r];//    r    'r',     buf      
            i = q;
            if (i == 0) break;
        }
        if (sign != 0) {//      ,   '-'
            buf [--charPos] = sign;
        }
    }
    

    이곳에는 몇 가지 비교적 재미있는 곳이 있다.
  • 먼저 단락을 나누어 문자를 얻는다. >=65535와 <65535 두 단락으로 나누면 65535와 같은 부분보다 크고 매번 두 문자를 교체해서 얻는다. 여기서 궁금한 것은 왜 >=10과 <10 두 부분으로 나누지 않는가. 설마 뒤에 있는 이 단락 코드의 실행 속도가 비교적 빠른 건 아니겠지?
  • 그 다음은 <65535 이 부분이다. q = (i * 52429) >>> (16+3);에 대해 이 코드는 q = i / 10;와 같고 ALU가 곱셈과 위치 이동 연산을 집행하는 속도가 제곱법의 연산 속도보다 빠를 것이다.그러나 왜 52429과 2^19(2의 19차원, 무기호 오른쪽으로 19자리를 옮기는 것은 2를 제외한 19차원)에 해당하는지 정밀도가 동시에 넘치지 않도록 고려한 것이다.먼저 정밀도에 대해 말하자면 (double) 52429/52488=0.100000381469, 이 정밀도는 i의 10분의 1을 구할 수 있다. 예를 들어 정밀도가 부족한 것을 골라서 0.103을 구한다면 i가 999999*0.103=102이고 999의 10분의 199가 아니다.한편, 65536=2^16524229<65536, 그래서 i*52429<2^32, 넘치지 않고 i*52429는 결과가 마이너스로 변하는 문제를 초래할 수 있다. 이것은 중간 결과일 뿐이다. 부호가 없이 19위를 오른쪽으로 이동한 후에 높은 위치가 모두 0을 보충하면 결과는 q가 정수이다.이상에서 알 수 있듯이 jdk는 여전히 매우 엄격하고 효율을 위해 노력했다.
  • 그러나 실제 테스트 결과 연산 효율이 크게 향상되지 않은 것으로 느껴졌고 예전의 ALU가 현재의 선진적이지 않은 것으로 보인다.

  • toString(int, int)
    다음은 toString (int i, int radix) 을 보십시오. 이 방법은 주로 형삼 i를 radix 진법으로 바꾸는 것입니다.
    public static String toString(int i, int radix) {
        //     2     36  ,  10    
        if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
            radix = 10;
    
        /* Use the faster version */
        // 10   ,         
        if (radix == 10) {
            return toString(i);
        }
    
        // Integer    33 ,  32 ,  1 
        char buf[] = new char[33];
        boolean negative = (i < 0);//        ,  i          
        int charPos = 32;// buf      , 32  
    
        //   i   ,  ,      
        if (!negative) {
            i = -i;
        }
    
        // i%radix         buf    (charPos)  
        while (i <= -radix) {
            buf[charPos--] = digits[-(i % radix)];
            i = i / radix;
        }
        buf[charPos] = digits[-i];
    
        //   i   ,  '-'
        if (negative) {
            buf[--charPos] = '-';
        }
        //      , buf charPos      ,  33-charPos,         ,     32
        return new String(buf, charPos, (33 - charPos));
    }
    

    toString()
    인덱스가 봉인된value를 문자열로 바꾸는 것은 어렵지 않습니다.
    public String toString() {
        return toString(value);
    }
    

    toHexString(int)
    다음은 몇 개의 무기호 진법의 전환을 보겠습니다.
    public static String toHexString(int i) {
        return toUnsignedString(i, 4);
    }
    public static String toOctalString(int i) {
        return toUnsignedString(i, 3);
    }
    public static String toBinaryString(int i) {
        return toUnsignedString(i, 1);
    }
    /**
     *            
     *       ,                    , 17  0000 0000 0000 0000 0000 0001 0001 0001,-17  1111 1111 1111 1111 1111 1111 1110 1111
     */
    private static String toUnsignedString(int i, int shift) {
        //     ,   32   
        char[] buf = new char[32];
        //         
        int charPos = 32;
        //   
        int radix = 1 << shift;
        //        ,        0001,     0111,      1111
        int mask = radix - 1;
        do {
            //     i & mask,              ,      ,         , 0001 0001  8  , 3   :00 010 001,    0 2 1,  17 8      21,i & mask       ,     mask       ,   digits        
            buf[--charPos] = digits[i & mask];
            i >>>= shift;
        } while (i != 0);
    
        return new String(buf, charPos, (32 - charPos));
    }
    

    i & mask의 과정을 보여 줍니다.
  • i=17,mask=7은 0001 0001 & 0111 001, digit[1]=1, 2차 교체 i=000 010000 010 & 0111 010, digit[2]=2, 교체 종료,buf=21에 해당한다.
  • i=17,mask-15는 0001 0001 & 1111은 0001, digit[1]=1, 2차 교체 i=00010001 & 1111은 0001, digit[1]=1, 교체 끝,buf=11에 해당한다.

  • parseInt(String, int)
    다음으로parseInt 방법, 진법 변환의 공식을 보겠습니다. a*radix^0+b*radix^1+c*radix^2+...+xx * radix^(n-1)
    /**
     *                         
     * 
     */
    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.
         */
    
        //       s    ,     [2, 36],    jdk         ,       ,  [2, 36]     10    ,      ,     
        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;
        //             ,        ,  Integer.MIN_VALUE       
        boolean negative = false;
        int i = 0, len = s.length();
        //              
        int limit = -Integer.MAX_VALUE;
        //     ,        
        int multmin;
        //   Character#digit       
        int digit;
    
        if (len > 0) {
            //        
            char firstChar = s.charAt(0);
            if (firstChar < '0') { // Possible leading "+" or "-"
                if (firstChar == '-') {
                    negative = true;
                    //      ,      Integer.MIN_VALUE
                    limit = Integer.MIN_VALUE;
                } else if (firstChar != '+')
                    throw NumberFormatException.forInputString(s);
    
                if (len == 1) // Cannot have lone "+" or "-"
                    throw NumberFormatException.forInputString(s);
                i++;
            }
            //          ,  10     211, multmin = 211 / 10 = 21,    result 30,       result *= radix     211,   。
            multmin = limit / radix;
            while (i < len) {
                // Accumulating negatively avoids surprises near MAX_VALUE
                //     ,   Character   
                digit = Character.digit(s.charAt(i++),radix);
                if (digit < 0) {
                    throw NumberFormatException.forInputString(s);
                }
                //        (limit   )  ,      result > multmin
                if (result < multmin) {
                    throw NumberFormatException.forInputString(s);
                }
                result *= radix;//   ,     a * radix^(n-1)   
                //           ,       ,result   210,  digit 2,     result = 212,     。
                if (result < limit + digit) {
                    throw NumberFormatException.forInputString(s);
                }
                result -= digit;//         ,       
            }
        } else {
            throw NumberFormatException.forInputString(s);
        }
        return negative ? result : -result;
    }
    //            
    public static int parseInt(String s) throws NumberFormatException {
      return parseInt(s,10);
    }
    

    valueOf()
    이어서valueOf 방법을 살펴보자.valueOf 방법을 보기 전에 Integer Cache를 먼저 보아야 한다. 말 그대로 이것은 정수의 캐시이다. 기본적으로 Integet Cache는 [-128,127]의 모든 실례를 캐시하기 때문에 정상적인 상황에서 이 두 값 범위 내의 이미지는 모두 같다(=true). 왜냐하면 그들은 같은 메모리의 대상을 인용하기 때문이다.예를 들면, 당연히 시작 매개 변수-XX:AutoBoxCacheMax=size를 통해 캐시의 내용을 수정할 수 있다. (size는 127보다 커야 하고, 그렇지 않으면 127로 간주해서 jvm의 캐시를 [-size-1,size]의 대상으로 할 수 있다.코드 보기:
    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) {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);//        127 ,      127
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                }
                high = h;
    
                cache = new Integer[(high - low) + 1];
                int j = low;
                //          , cache    
                for(int k = 0; k < cache.length; k++)
                    cache[k] = new Integer(j++);
            }
    
            private IntegerCache() {}
        }
    

    구체적으로 value Of 방법을 보십시오
    //    parseInt       
    public static Integer valueOf(String s, int radix) throws NumberFormatException {
      return Integer.valueOf(parseInt(s,radix));
    }
    public static Integer valueOf(String s) throws NumberFormatException {
      return Integer.valueOf(parseInt(s, 10));
    }
    public static Integer valueOf(int i) {
      assert IntegerCache.high >= 127;//   IntegetCache      127
      //  [IntegetCache.low, Integer.high]           
      if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
      return new Integer(i);//         
    }
    

    나누기가 쉽지 않으니, 옮겨 싣고 출처를 밝혀 주십시오.
    java.lang.Integer 소스 읽기 (1) 주소:https://www.jianshu.com/p/02c1d9092347

    좋은 웹페이지 즐겨찾기