包装类:Integer、Long、Short、Boolean、Byte、Character、Double、Float、Number
Integer:
方法 |
---|
类 |
构造函数 |
内部类 |
valueOf |
stringSize |
signum |
getChars |
toString |
parseInt |
hashCode |
decode |
highestOneBit |
lowestOneBit |
numberOfTrailingZeros |
numberOfLeadingZeros |
public final class Integer extends Number implements Comparable<Integer>
构造函数
public Integer(int value) {
this.value = value;
}
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
内部类
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
Integer的内部类IntegerCache
做什么用的?
- 从字面意思理解,他是一个缓存
- 它内部有一个Integer类型的常量数组,一般的这个high没有指定的时候,i就为127,h也为127,那么缓存的大小就是high-low+1,其实就是正数部分+负数部分+0,对于high未指定的情况下,这个缓存的大小就是256,表示[-128,127]
- 它的内部是一个静态代码块,它在程序的运行当中只会被执行一次
-当我们Integer n1=127;
这个Integer就是来自IntegerCahche里面的数
- 举个栗子
public class Main{
public static void main(String[] args) {
Integer n1 = 127;
Integer n2 = 127;
Integer n3 = 128;
Integer n4 = 128;
System.out.println(n1 == n2);
System.out.println(n3 == n4);
}
结果:true、false
原因:从Integer.valueOf()方法得知,[-128,127]里的数字自动装箱的时候是从IntegerCahce中使用的,而大于127时,是new Integer(value)
自动装箱的时候是调用的Integer.valueOf()方法
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
public static Integer valueOf(String s, int radix) throws NumberFormatException {
return Integer.valueOf(parseInt(s,radix));
}
-
stringSize(int i)
一个蛮巧妙的函数
用于计算要储存整数的string数组大小,正数
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE };
// Requires positive x
static int stringSize(int x) {
for (int i=0; ; i++)
if (x <= sizeTable[i])
return i+1;
}
-
signum(int i)
由于Integer的value值是int类型,是32位二进制位数,最高位是符号位
正数:(i>>31)=0 ( -i>>>31)=1 0|1=1
负数:(i>>31)=-1 ( -i>>>31)=0 -1|0=-1
基础知识:
- 正数的符号位是0,负数的符号位是1
- 正数的表示形式是原码,负数的表示形式是补码
- 负数补码的求法: 原码符号位不变,其他位按位取反后加1
- >> 符号是0,右移后左侧高位补0,是1补1
- >>> 无论高位是0还是1,左侧高位都补0
public static int signum(int i) {
// HD, Section 2-7
return (i >> 31) | (-i >>> 31);
}
- getChars(int i, int index, char[] buf)
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'
};
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);
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;
}
}
三个参数
- i: 要被转成字符串的数字
- index: 数字的各位在数组中的位置,一般的也就是数字的位数,小于数字的位数就会报ArrayIndexOutOfBoundsException,大于数字的位数之后就会将数字在数组位置后移
- buf: 数字转字符数组转换后的结果
示例:
int i=-1234;
char[] buf1=new char[5];
char[] buf2=new char[7];
getChars(i,5,buf1);
getChars(i,6,buf2);
System.out.println(Arrays.toString(buf1));
System.out.println(Arrays.toString(buf2));
结果:
[-, 1, 2, 3, 4]
[ , -, 1, 2, 3, 4, ]
这个函数设计非常的巧,当然我们使用普通的写法也能实现将数字转化为字符串数组,然而效率和时间复杂度当然也就比较的普通吧,这可能就是自己与大佬的区别吧。
思路其实很简单,第一步:判断正负,根据正负来处理;第二步:将大于等于65535的数(2^16-1)除以100,然后求取余数,然后再去常量数组里取出字符串,赋值。然后小于65535的数,除以10,求取余数,然后再去常量数组里取出字符串,赋值。
- toString
如果是10进制,则直接调用toString(int i),toString(int i)最终调用getChars实现转换。其他进制就是除radix取余
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);
}
public static String toString(int i, int radix) {
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
radix = 10;
/* Use the faster version */
if (radix == 10) {
return toString(i);
}
char buf[] = new char[33];
boolean negative = (i < 0);
int charPos = 32;
if (!negative) {
i = -i;
}
while (i <= -radix) {
buf[charPos--] = digits[-(i % radix)];
i = i / radix;
}
buf[charPos] = digits[-i];
if (negative) {
buf[--charPos] = '-';
}
return new String(buf, charPos, (33 - charPos));
}
toBinaryString、toOctalString、toHexString都调用了toUnsignedString0函数
public static String toBinaryString(int i) {
return toUnsignedString0(i, 1);
}
public static String toOctalString(int i) {
return toUnsignedString0(i, 3);
}
public static String toHexString(int i) {
return toUnsignedString0(i, 4);
}
private static String toUnsignedString0(int val, int shift) {
// assert shift > 0 && shift <=5 : "Illegal shift value";
int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
int chars = Math.max(((mag + (shift - 1)) / shift), 1);
char[] buf = new char[chars];
formatUnsignedInt(val, shift, buf, 0, chars);
// Use special constructor which takes over "buf".
return new String(buf, true);
}
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;
}
static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
int charPos = len;
int radix = 1 << shift;
int mask = radix - 1;
do {
buf[offset + --charPos] = Integer.digits[val & mask];
val >>>= shift;
} while (val != 0 && charPos > 0);
return charPos;
}
算法很精妙,读起来真的也还是容易懂,写起来却有点困难,标记一下,后面手写实现。
- parseInt
public static final int MIN_RADIX = 2;
public static final int MAX_RADIX = 36;
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.
*/
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) {
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++;
}
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;
}
Integer.parseInt原理其实很简单,但是java源码实现得却不简单,自己暂时没有时间深入研究一下,在这里标记一下,后面有时间再分析分析
-
hashCode
与String不同的是,Integer的hash值就是他本身
public static int hashCode(int value) {
return value;
}
-
decode(String nm)
将"0xff","-1","077","#ff55ff"转换成Integer
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;
}
- highestOneBit
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);
}
就是返回最高位的数字
1.当i>0时,返回的则是跟它最靠近的比它小的2的N次方
2.当i=0;返回0。
3.当i<0,返回Integer.MIN_VALUE.
参考腾讯云的博客https://cloud.tencent.com/developer/article/1332309
- lowestOneBit
public static int lowestOneBit(int i) {
// HD, Section 2-1
return i & -i;
}
- numberOfTrailingZeros
尾部的0的位数
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);
}
- numberOfLeadingZeros
头部的0的位数
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;
}
Integer除上面这些方法外,还有rotateLeft,rotateRight,reverse等方法,但是我觉得用处不是特别大,后面有需要的时候再看吧
网友评论