• 作业11:包装类与基础类型


    一 以整型为例剖析拆箱装箱

    1 基本比较

    (1)java代码

    Integer int1 = new Integer("1");
    int int2 = 1;
    System.out.println(int1 == int2);
    

    (2)java反编译代码

     Code:
           0: new           #2                  // class java/lang/Integer
           3: dup							 // 复制栈顶数值并将复制值压入栈顶
           4: ldc           #3                  // 将常量值从常量池中推送至栈顶
           6: invokespecial #4                  // Method java/lang/Integer."<init>":(Ljava/lang/String;)V
           9: astore_1                          // 将栈顶引用型数值存入第二个本地变量,int1
          10: iconst_1                          // 将int型(1)推送至栈顶 
          11: istore_2                          // 将栈顶int型数值存入第三个本地变量,int2
          12: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
          15: aload_1                           // 将第二个引用类型本地变量推送至栈顶
          16: invokevirtual #6                  // Method java/lang/Integer.intValue:()I
          19: iload_2
          20: if_icmpne     27                  // 比较栈顶两int型数值大小,当结果不等于0时跳转
          23: iconst_1
          24: goto          28
          27: iconst_0
          28: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
          31: return
     
    // 第11行 ==> 16:invokevirtual,很明显知道调用Integer.intValue方法(拆箱,执行效率很高)
    // 第20行 ==> 进行int类型的比较
    

    (3)相关JDK源码

    private final int value;
    
    @Deprecated(since="9") // java9过时方法
    public Integer(String s) throws NumberFormatException {
        this.value = parseInt(s, 10);
    }
    
    // 字符串解析为数字的方法
    public static int parseInt(String s, int radix) throws NumberFormatException{
        if (s == null) {
            throw new NumberFormatException("null");
        }
    	// Integer上下界判断
        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");
        }
    
        boolean negative = false;
        int i = 0, len = s.length();
        int limit = -Integer.MAX_VALUE;
    
        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++;
            }
            int multmin = limit / radix;
            int result = 0;
            while (i < len) {
                int digit = Character.digit(s.charAt(i++), radix);
                if (digit < 0 || result < multmin) {
                    throw NumberFormatException.forInputString(s);
                }
                result *= radix;
                if (result < limit + digit) {
                    throw NumberFormatException.forInputString(s);
                }
                result -= digit;
            }
            return negative ? result : -result;
        } else {
            throw NumberFormatException.forInputString(s);
        }
    }
    
    // hotspot热点方法指定
    @HotSpotIntrinsicCandidate 
    public int intValue() {
        return value;
    }
    

    2 比较缓存范围内的包装类

    (1)java代码

    // 缓存范围:-128~127
    Integer int1 = Integer.valueOf(127); 
    Integer int2 = 127; // 装箱,Integer.valueOf(127);
    System.out.println(int1 == int2); // true
    

    (2)字节码

     Code:
           0: bipush        127                 // 将单字节的常量值(-128~127)推送至栈顶,超出使用ldc,但排除-1~5,该区间使用iconst方式
           2: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
           5: astore_1
           6: bipush        127
           8: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 装箱的秘密
          11: astore_2
          12: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
          15: aload_1
          16: aload_2
          17: if_acmpne     24
          20: iconst_1                          // true,常量值1入栈
          21: goto          25                  // 无条件跳转
          24: iconst_0                          // false,常量值0入栈
          25: invokevirtual #4                  // Method java/io/PrintStream.println:(Z)V
          28: return
          
    # 注意:bipush范围-128~127(单字节),sipush范围-32768~32767(双字节),ldc范围Integer.MIN_VALUE~Integer.MAX_VALUE
    # ldc 能将整型、浮点型、字符串类型的常量值从常量池推到栈顶
    

    3 比较缓存范围外的包装类

    (1)java代码

    Integer int1 = Integer.valueOf(128); 
    Integer int2 = 128; // 装箱,Integer.valueOf(128);
    System.out.println(int1 == int2); // false
    

    (2)相关的JDK源码

    @HotSpotIntrinsicCandidate
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high) // 范围内则取缓存,否则new对象
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
    
    private static class IntegerCache {
            static final int low = -128;
            static final int high;
       		static final Integer cache[];
    		
        	 static {
                int h = 127; // 默认:127
                // 可通过配置修改,修改方式:-Djava.lang.Integer.IntegerCache.high=<size> 
                String integerCacheHighPropValue = VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
                if (integerCacheHighPropValue != null) {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127); // 最大值至少为127
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                }
                high = h;
    
                cache = new Integer[(high - low) + 1];
                int j = low;
                for(int k = 0; k < cache.length; k++)
                    cache[k] = new Integer(j++); // 类加载过程默认创建大于等于256个Integer对象
            }
    
            private IntegerCache() {}
    }
    
    

    IntegerCache的high值修改,请参考:https://stackoverflow.com/questions/15052216/how-large-is-the-integer-cache

    4 疑惑

    (1)java代码

    System.out.println(1); // 1
    System.out.println(true); // true
    

    (2)字节码

    Code:
           0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
           3: iconst_1                          // int(1)入栈
           4: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
           7: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
          10: iconst_1                          // int(1)入栈
          11: invokevirtual #4                  // Method java/io/PrintStream.println:(Z)V
          14: return
    

    (3)静态常量池

    #03 (Methodref):java/io/PrintStream.println
    	tag: 10
    	class_index:23
    	name_and_type_index:24
    #04 (Methodref):java/io/PrintStream.println
    	tag: 10
    	class_index:23
    	name_and_type_index:25
    	
    #24 (NameAndType):println&(I)V
    	tag: 12
    	class_index:32
    	name_and_type_index:33
    #25 (NameAndType):println&(Z)V
    	tag: 12
    	class_index:32
    	name_and_type_index:34
    	
    #33 (Utf8):(I)V // I代表int类型
    	tag: 1
    	length:4
    	bytes:(I)V	
    #34 (Utf8):(Z)V // Z代表boolean类型,具体参考jvm规范
    	tag: 1
    	length:4
    	bytes:(Z)V
    

    jvm规范下载地址:https://docs.oracle.com/javase/specs/index.html

    (4)总结:

    • 字节码中int(1)与boolean(true)都用int(1)表示。
    • println的重载方法,传入了类型,将相同int(1)输出了不同的结果。

    5 Integer相加

    (1)java代码

    Integer i1 = 1;
    Integer i2 = 2;
    Integer i3 = i1 + i2; // 实际上是拆箱相加再装箱
    

    (2)字节码

    Code:
           0: iconst_1
           1: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
           4: astore_1
           5: iconst_2
           6: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
           9: astore_2
          10: aload_1
          11: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
          14: aload_2
          15: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
          18: iadd								// 将栈顶两int型数值相加并将结果压入栈顶
          19: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
          22: astore_3
          23: return
    

    6 Integer与基础类型比较

    (1)java代码

    Integer i1 = 1;
    byte i2 = 1;
    short i3 = 1;
    long i4 = 1l;
    float i5 = 1.0f;
    double i6 = 1.0;
    System.out.println(i1 == i2); 
    System.out.println(i1 == i3);
    System.out.println(i1 == i4);// Integer -> int -> long -> long比较 -> 结果为1 -> true
    System.out.println(i1 == i5);// Integer -> int -> float -> float比较 -> 结果为1 -> true
    System.out.println(i1 == i6);// Integer -> int -> double-> double比较 -> 结果为1 -> true
    

    (2)字节码

    Code:
           0: iconst_1
           1: istore_1
           2: iconst_1
           3: istore_2
           4: iconst_1
           5: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
           8: astore_3
           9: lconst_1
          10: lstore        4
          12: fconst_1
          13: fstore        6
          15: dconst_1
          16: dstore        7
          18: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
          21: aload_3
          22: invokevirtual #4                  // Method java/lang/Integer.intValue:()I
          25: iload_2
          26: if_icmpne     33
          29: iconst_1
          30: goto          34
          33: iconst_0
          34: invokevirtual #5                  // Method java/io/PrintStream.println:(Z)V
          37: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
          40: aload_3
          41: invokevirtual #4                  // Method java/lang/Integer.intValue:()I
          44: iload_1
          45: if_icmpne     52
          48: iconst_1
          49: goto          53
          52: iconst_0
          53: invokevirtual #5                  // Method java/io/PrintStream.println:(Z)V
          56: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
          59: aload_3
          60: invokevirtual #4                  // Method java/lang/Integer.intValue:()I
          63: i2l
          64: lload         4
          66: lcmp
          67: ifne          74
          70: iconst_1
          71: goto          75
          74: iconst_0
          75: invokevirtual #5                  // Method java/io/PrintStream.println:(Z)V
          78: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
          81: aload_3
          82: invokevirtual #4                  // Method java/lang/Integer.intValue:()I
          85: i2f
          86: fload         6
          88: fcmpl
          89: ifne          96
          92: iconst_1
          93: goto          97
          96: iconst_0
          97: invokevirtual #5                  // Method java/io/PrintStream.println:(Z)V
         100: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
         103: aload_3
         104: invokevirtual #4                  // Method java/lang/Integer.intValue:()I
         107: i2d
         108: dload         7
         110: dcmpl
         111: ifne          118
         114: iconst_1
         115: goto          119
         118: iconst_0
         119: invokevirtual #5                  // Method java/io/PrintStream.println:(Z)V
         122: return
    

    7 总结

    • 包装类之间:包装类与对应类型的包装类进行比较,如:Integer 与 Integer可以比较,Integer与Long不能比较。
    • 包装类与基础类型:包装类能够与任何基础类型比较,比较时先拆箱,int long float double则再根据数据类型级别: byte–>short–>int–>long–>double<–float进行转化,最后比较得出结果。
    • 其中byte short int之间的比较都是基于int类型比较。

    二 包装类

    1 Boolean类

    (1)JDK源码

    // Boolean
    public final class Boolean implements java.io.Serializable,Comparable<Boolean>{
    	// 由于Boolean只有true和false,直接定义两个常量
        public static final Boolean TRUE = new Boolean(true);
    
        public static final Boolean FALSE = new Boolean(false);
        
        public static Boolean valueOf(boolean b) {
            return (b ? TRUE : FALSE);
        }
        
        // 值得关注的是由于只有true和false,hash值也是固定的。
        public static int hashCode(boolean value) {
            return value ? 1231 : 1237;
        }
        
        // 当系统属性为"true"时,返回true;其余返回false。
        public static boolean getBoolean(String name) {
            boolean result = false;
            try {
                result = parseBoolean(System.getProperty(name));
            } catch (IllegalArgumentException | NullPointerException e) {
            }
            return result;
        }
        
    	// 1.8新增了逻辑运算的静态方法 
        public static boolean logicalAnd(boolean a, boolean b) {
            return a && b;
        }
    
        public static boolean logicalOr(boolean a, boolean b) {
            return a || b;
        }
    
        public static boolean logicalXor(boolean a, boolean b) {
            return a ^ b;
        }
    	......
    }
    

    (2) 测试方法

    // 由于Boolean比较简单,只对getBoolean方法进行测试
    // 其他感兴趣记得自己去测一测哦
    public static void main(String[] args) {
        System.setProperty("test1", "true");
        System.out.println(Boolean.getBoolean("test1")); //true
        System.setProperty("test2", "helloworld");
        System.out.println(Boolean.getBoolean("test1")); //false
    }
    

    2 Byte类

    (1)JDK源码

    public final class Byte extends Number implements Comparable<Byte> {
    	
        // 与Integer类似,但是由于Byte总共就256个,直接狗缓存起来了。
        private static class ByteCache {
            private ByteCache(){}
    
            static final Byte cache[] = new Byte[-(-128) + 127 + 1];
    
            static {
                for(int i = 0; i < cache.length; i++)
                    cache[i] = new Byte((byte)(i - 128));
            }
        }
        
        // valueOf方法采用数组偏移量来获取,应为chache[128]正好是0.
        public static Byte valueOf(byte b) {
            final int offset = 128;
            return ByteCache.cache[(int)b + offset];
        }
    	
        public static byte parseByte(String s, int radix) throws NumberFormatException {
            int i = Integer.parseInt(s, radix); // 借助Integer的静态方法
            if (i < MIN_VALUE || i > MAX_VALUE) // 上界下界比较
                throw new NumberFormatException("Value out of range. Value:"" + s + "" Radix:" + radix);
            return (byte)i;
        }
        
        public static int hashCode(byte value) {
           return (int)value;
        }
        
        // 1.8新增的工具方法和属性
        
        // 占用多少字节
        public static final int BYTES = SIZE / Byte.SIZE;
        
        public static int toUnsignedInt(byte x) {
            return ((int) x) & 0xff;
        }
        
        public static long toUnsignedLong(byte x) {
            return ((long) x) & 0xffL;
        }
        
        public static int compareUnsigned(byte x, byte y) {
            return Byte.toUnsignedInt(x) - Byte.toUnsignedInt(y);
        }
    }
    

    (2)测试

    // 这个类也比较简单啦,就测试个缓存吧
    public static void main(String[] args) {
        Byte aByte = Byte.valueOf((byte)127);
        Byte bByte = 127;
        System.out.println(aByte == bByte); // true,啰嗦一句,相同包装类型比较不涉及拆箱
    }
    

    3 Short类的JDK源码

    public final class Short extends Number implements Comparable<Short> {
        // 与Byte的居然一模一样,而IntegerCache能够修改上界
        private static class ShortCache {
            private ShortCache(){}
    
            static final Short cache[] = new Short[-(-128) + 127 + 1];
    
            static {
                for(int i = 0; i < cache.length; i++)
                    cache[i] = new Short((short)(i - 128));
            }
        }
        
        // 与Byte一样的工具类不列出来了,自己感兴趣去看看
        
        // 通过位运算得出:高8位与低8位互换位置
        // 用途:内存存储模式不同,有大端模式和小端模式。X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。为了适配不同的处理器而做的??
        @HotSpotIntrinsicCandidate
        public static short reverseBytes(short i) {
            return (short) (((i & 0xFF00) >> 8) | (i << 8));
        }
    }
    

    4 Integer类

    (1)JDK源码

    public final class Integer extends Number implements Comparable<Integer> {
        // int -> String 
        @HotSpotIntrinsicCandidate
        public static String toString(int i) {
            int size = stringSize(i);
            if (COMPACT_STRINGS) { // 字符串编码格式,LATIN1,则字节表示
                byte[] buf = new byte[size];
                getChars(i, size, buf); // 为什么不像StringUTF16一样也创建一个StringLATIN1类,并把这个工具类放过去?
                return new String(buf, LATIN1);
            } else { // UTF16,则字符表示,2个字节。
                byte[] buf = new byte[size * 2];
                StringUTF16.getChars(i, size, buf);
                return new String(buf, UTF16);
            }
        }
        
        // 由于有正负之分,所以都变为负数进行获取String长度
        // Integer 无符号最大值为4294967296(10位数字)
        static int stringSize(int x) {
            int d = 1;
            if (x >= 0) {
                d = 0;
                x = -x;
            }
            int p = -10;
            for (int i = 1; i < 10; i++) {
                if (x > p)
                    return i + d;
                p = 10 * p;
            }
            return 10 + d; // 最大10位数 + d(正数为0/负数为1) = 10 或者11.
        }
        
        /**
        * 以100为单位进行数字 -> byte[]
        */
        static int getChars(int i, int index, byte[] buf) {
            int q, r;
            int charPos = index;
    
            boolean negative = i < 0;
            if (!negative) {
                i = -i;
            }
    
            // Generate two digits per iteration
            while (i <= -100) {
                q = i / 100;
                r = (q * 100) - i;
                i = q;
                buf[--charPos] = DigitOnes[r];
                buf[--charPos] = DigitTens[r];
            }
    
            // We know there are at most two digits left at this point.
            q = i / 10;
            r = (q * 10) - i;
            buf[--charPos] = (byte)('0' + r);
    
            // Whatever left is the remaining digit.
            if (q < 0) {
                buf[--charPos] = (byte)('0' - q);
            }
    
            if (negative) {
                buf[--charPos] = (byte)'-';
            }
            return charPos;
        }
        
        // 从系统参数中获取Integer值
        public static Integer getInteger(String nm, Integer val) {
            String v = null;
            try {
                v = System.getProperty(nm);
            } catch (IllegalArgumentException | NullPointerException e) {
            }
            if (v != null) {
                try {
                    return Integer.decode(v);
                } catch (NumberFormatException e) {
                }
            }
            return val;
        }
        
        /**
        * 字符串 -> Integer
        * 支持:10进制、8进制、16进制
        */
        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;
        }
        
        // 除法
        public static int divideUnsigned(int dividend, int divisor) {
            // In lieu of tricky code, for now just use long arithmetic.
            return (int)(toUnsignedLong(dividend) / toUnsignedLong(divisor));
        }
        
        // 取余
        public static int remainderUnsigned(int dividend, int divisor) {
            // In lieu of tricky code, for now just use long arithmetic.
            return (int)(toUnsignedLong(dividend) % toUnsignedLong(divisor));
        }
        
        @HotSpotIntrinsicCandidate
        public static int reverseBytes(int i) {
            return (i << 24)            |
                   ((i & 0xff00) << 8)  |
                   ((i >>> 8) & 0xff00) |
                   (i >>> 24);
        }
        
        // 值得注意的是Java9的方法:字符序列截取获取int值
        // 用途:日期字符串、IP地址字符串、时间戳字符串都可以用这个来转化很方便,不需要创建新的字符串进行解析,节省了系统资源。
        public static int parseInt(CharSequence s, int beginIndex, int endIndex, int radix)
                    throws NumberFormatException {
            s = Objects.requireNonNull(s);
    
            if (beginIndex < 0 || beginIndex > endIndex || endIndex > s.length()) {
                throw new IndexOutOfBoundsException();
            }
            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");
            }
    
            boolean negative = false;
            int i = beginIndex;
            int limit = -Integer.MAX_VALUE;
    
            if (i < endIndex) {
                char firstChar = s.charAt(i);
                if (firstChar < '0') { // Possible leading "+" or "-"
                    if (firstChar == '-') {
                        negative = true;
                        limit = Integer.MIN_VALUE;
                    } else if (firstChar != '+') {
                        throw NumberFormatException.forCharSequence(s, beginIndex,
                                endIndex, i);
                    }
                    i++;
                    if (i == endIndex) { // Cannot have lone "+" or "-"
                        throw NumberFormatException.forCharSequence(s, beginIndex,
                                endIndex, i);
                    }
                }
                int multmin = limit / radix;
                int result = 0;
                while (i < endIndex) {
                    // Accumulating negatively avoids surprises near MAX_VALUE
                    int digit = Character.digit(s.charAt(i), radix);
                    if (digit < 0 || result < multmin) {
                        throw NumberFormatException.forCharSequence(s, beginIndex,
                                endIndex, i);
                    }
                    result *= radix;
                    if (result < limit + digit) {
                        throw NumberFormatException.forCharSequence(s, beginIndex,
                                endIndex, i);
                    }
                    i++;
                    result -= digit;
                }
                return negative ? result : -result;
            } else {
                throw NumberFormatException.forInputString("");
            }
        }
    }
    

    (2)测试

    // 简单测试几个不常用的
    public static void main(String[] args) {
        Integer decode = Integer.decode("0xff");
        System.out.println(decode);// 255
        int i = Integer.divideUnsigned(9, 2);
        System.out.println(i); // 4
        String dateStr = "2018-08-25";
        int yearEndIndex = dateStr.indexOf('-');
        int monthEndIndex = dateStr.lastIndexOf('-');
        int year = Integer.parseInt(dateStr, 0, yearEndIndex, 10);
        int month = Integer.parseInt(dateStr, yearEndIndex + 1, monthEndIndex, 10);
        int day = Integer.parseInt(dateStr, monthEndIndex + 1, dateStr.length(), 10);
        System.out.println(year);// 2018
        System.out.println(month);// 8
        System.out.println(day);// 25
    }
    

    5 Long类

    (1)JDK源码

    public final class Long extends Number implements Comparable<Long> {
        // 这个方法注意下:我们平常使用的UUID.randomUUID().toString()其实用到了该方法。
        // 调用关系 UUID.toString -> System.fastUUID -> Long.fastUUID
        // TODO:这条调用关系涉及内容比较多,以后另外研究一下再写篇博客。
        static String fastUUID(long lsb, long msb) {
            if (COMPACT_STRINGS) {
                byte[] buf = new byte[36];
                formatUnsignedLong0(lsb,        4, buf, 24, 12);
                formatUnsignedLong0(lsb >>> 48, 4, buf, 19, 4);
                formatUnsignedLong0(msb,        4, buf, 14, 4);
                formatUnsignedLong0(msb >>> 16, 4, buf, 9,  4);
                formatUnsignedLong0(msb >>> 32, 4, buf, 0,  8);
    
                buf[23] = '-';
                buf[18] = '-';
                buf[13] = '-';
                buf[8]  = '-';
    
                return new String(buf, LATIN1);
            } else {
                byte[] buf = new byte[72];
    
                formatUnsignedLong0UTF16(lsb,        4, buf, 24, 12);
                formatUnsignedLong0UTF16(lsb >>> 48, 4, buf, 19, 4);
                formatUnsignedLong0UTF16(msb,        4, buf, 14, 4);
                formatUnsignedLong0UTF16(msb >>> 16, 4, buf, 9,  4);
                formatUnsignedLong0UTF16(msb >>> 32, 4, buf, 0,  8);
    
                StringUTF16.putChar(buf, 23, '-');
                StringUTF16.putChar(buf, 18, '-');
                StringUTF16.putChar(buf, 13, '-');
                StringUTF16.putChar(buf,  8, '-');
    
                return new String(buf, UTF16);
            }
        }
    
        // 固定-128~127
        private static class LongCache {
            private LongCache(){}
    
            static final Long cache[] = new Long[-(-128) + 127 + 1];
    
            static {
                for(int i = 0; i < cache.length; i++)
                    cache[i] = new Long(i - 128);
            }
        }
        
    }
    

    (2)测试

     public static void main(String[] args) {
         System.out.println(Long.bitCount(12L)); // 2,2进制形式有多少个1.
         System.out.println(Long.highestOneBit(12L)); // 8,2进制最高位的值多少。8 + 4 = 12
         System.out.println(Long.lowestOneBit(12L)); // 4,2进制最高位的值多少。8 + 4 = 12
         System.out.println(Long.signum(12L)); // 1,正负值
         System.out.println(Long.numberOfLeadingZeros(12L)); // 61,2进制最高位左边有多少个0.
         System.out.println(Long.numberOfTrailingZeros(12L)); // 2,2进制最低位右边有多少个0.
     }
    

    6 Character

    (1) JDK源码

    public final class Character implements java.io.Serializable, Comparable<Character> {
        // 0 ~ 127
    	private static class CharacterCache {
            private CharacterCache(){}
    
            static final Character cache[] = new Character[127 + 1];
    
            static {
                for (int i = 0; i < cache.length; i++)
                    cache[i] = new Character((char)i);
            }
        }
        
        // 词法分析器用到的方法,具体实现以后探究
        // 我们都字段只能以 _ $ 和 英文字母开头,如果用数字开头编译器会不通过,判断方式就是该方法
        public static boolean isJavaIdentifierStart(char ch) {
            return isJavaIdentifierStart((int)ch);
        }
        
    }
    

    (2)测试

    public static void main(String[] args) {
        System.out.println(Character.isJavaIdentifierStart('_'));// true
        System.out.println(Character.isJavaIdentifierStart('$'));// true
        System.out.println(Character.isJavaIdentifierStart('a'));// true
        System.out.println(Character.isJavaIdentifierStart('3'));// false
    }
    

    7 Float类

    (1)JDK源码

    public final class Float extends Number implements Comparable<Float> {
        // Float类型的值即使很小的区间也有无穷多个,所以它内部没有Cache
        
    	public static boolean isNaN(float v) {
            return (v != v); // 只有NaN不等于NaN,编译器器直接编译好,不需要调用jvm底层指令。
        }
        
        public static boolean isInfinite(float v) {
            return (v == POSITIVE_INFINITY) || (v == NEGATIVE_INFINITY);
        }
    }
    

    (2)测试

    public static void main(String[] args) {
        System.out.println(0.0f / 0.0f);// NaN产生方式
        System.out.println(1.0f / 0.0f);// Infinity产生方式
        System.out.println(Float.isNaN(0.0F / 0.0F)); // true
        System.out.println(Float.isFinite(1.0F / 1.0F)); //  true
        System.out.println(Float.isInfinite(-1.0F / 0.0F)); // true
    }
    

    (3)反编译(这次采用的是Idea的jclasslib插件)

     0 getstatic #2 <java/lang/System.out>
     3 ldc #3 <NaN>
     5 invokevirtual #4 <java/io/PrintStream.println>
     8 getstatic #2 <java/lang/System.out>
    11 ldc #5 <Infinity>
    13 invokevirtual #4 <java/io/PrintStream.println>
    16 getstatic #2 <java/lang/System.out>
    19 ldc #3 <NaN>
    21 invokestatic #6 <java/lang/Float.isNaN>
    24 invokevirtual #7 <java/io/PrintStream.println>
    27 getstatic #2 <java/lang/System.out>
    30 fconst_1
    31 invokestatic #8 <java/lang/Float.isFinite>
    34 invokevirtual #7 <java/io/PrintStream.println>
    37 getstatic #2 <java/lang/System.out>
    40 ldc #9 <-Infinity>
    42 invokestatic #10 <java/lang/Float.isInfinite>
    45 invokevirtual #7 <java/io/PrintStream.println>
    48 return
    

    8 Double类

    • 省略,与Float类差不多

    9 总结

    这一章就大概看一下包装类的部分方法,源码里面涉及东西太多,太过深入,这一期作业又做不完了,就暂且打住,有时间再单个击破。

  • 相关阅读:
    关于HTML(七)--------HTML废弃的标签
    关于HTML(六)--------canvas
    抓包神器之Charles,常用功能都在这里了(转自https://blog.csdn.net/mxw2552261/article/details/78645118)
    混合开发的坑(7) ---输入文本时,键盘遮挡
    关于HTML(五)---------meta标签
    关于HTML(四)---------使用data-的好处
    关于HTML(三)---------xhtml和html的区别
    关于HTML(二)---------浏览器的标准模式和怪异模式
    关于HTML(一)---------HTML5新特性2
    关于HTML(一)---------HTML5新特性1
  • 原文地址:https://www.cnblogs.com/linzhanfly/p/9537841.html
Copyright © 2020-2023  润新知