作业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 总结

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

posted @ 2018-08-26 16:57  月下小魔王  阅读(264)  评论(0编辑  收藏  举报