主要是参考了这篇博客
1.主要属性
@Native public static final int MIN_VALUE = 0x80000000;
// 值为 -2^31 的常量,它表示 int 类型能够表示的最小值。
@Native public static final int MAX_VALUE = 0x7fffffff;
// 值为 2^31-1 的常量,它表示 int 类型能够表示的最大值。
@Native public static final int SIZE = 32;
// 用来以二进制补码形式表示 int 值的比特位数。
public static final int BYTES = SIZE / Byte.SIZE;
// 返回int值所占的字节数。
public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
// 表示基本数据类型 int 的 Class 实例。
private final int value;//包装了一个基本类型int的值
2.构造方法
// 1、构造一个新分配的 Integer 对象,它表示指定的 int 值。
public Integer(int value) {
this.value = value;
}
// 2、构造一个新分配的 Integer 对象,它表示 String 参数所指定 int 值。
// 要注意的是字符串不能包含非数字字符,否则会抛出NumberFormatException
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
//3、除此之外,还可以给Integer对象直接赋值,如:
Integer a = 10;//涉及到自动装箱
3、bitCount方法
返回指定 int 值的二进制补码表示形式的是1的位数量,譬如Integer.bitCount(15),返回值为4。
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);
i = i + (i >>> 16);
return i & 0x3f;
}
4、xxxValue方法
// 以 byte 类型返回该 Integer 的值
public byte byteValue() {
return (byte)value;
}
// 以 short 类型返回该 Integer 的值
public short shortValue() {
return (short)value;
}
// 以 int 类型返回该 Integer 的值
public int intValue() {
return value;
}
// 以 long 类型返回该 Integer 的值
public long longValue() {
return (long)value;
}
// 以 float 类型返回该 Integer 的值
public float floatValue() {
return (float)value;
}
// 以 double 类型返回该 Integer 的值
public double doubleValue() {
return (double)value;
}
5、比较方法
// 比较x和y的值,当x大于y时返回1,当x等于y时返回0,否则返回-1
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
// 在数值上比较两个Integer对象
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
6、equals方法
比较此对象与指定对象是否相等 。首先判断指定对象是否为Integer类型,在判断两者 int 的值是否相等。
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
7、hashCode方法
返回此对象的哈希码 。
public int hashCode() {
return Integer.hashCode(value);
}
8、int—>String、String—>int方法
int—>String
static String toString(int i);
// Integer类中的静态方法,可以返回一个表示指定整数的 String 对象。
//其他方法:String类中有valueOf方法; 和""(空字符串)进行拼接。
String—>int
static int parseInt(String s)
//将字符串参数作为有符号的十进制整数进行解析,返回一个和字面值一样的int型数据。
static Integer valueOf(String s)
//返回保存指定的 String 值的 Integer 对象,然后调用intValue方法,获取int值。
9、进制转换方法
static String toBinaryString(int i)
//以二进制(基数 2)无符号整数形式返回一个整数参数的字符串表示形式
static String toHexString(int i)
//以十六进制(基数 16)无符号整数形式返回一个整数参数的字符串表示形式
static String toOctalString(int i)
//以八进制(基数 8)无符号整数形式返回一个整数参数的字符串表示形式
10、其他
1)装箱和拆箱
Integer i = 100; //自动装箱
i += 200; //自动拆箱
int ii = i.intValue(); //手动拆箱
Integer i1 = Integer.valueOf(100);//手动装箱
2)int和Integer
Integer是int的包装类,int则是java的一种基本数据类型;Integer变量必须实例化后才能使用,而int变量不需要;Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象(堆中);而int则是直接存储数据值 (栈中);Integer的默认值是null,int的默认值是0。
由于Integer变量实际上是一个Integer对象的引用,所以两个通过new生成的Integer变量永远是不相等的(因为new生成的是两个对象,其内存地址不同)。
Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.print(i == j); //false
Integer变量和int变量比较时,只要两个变量的值是相等的,则结果为true(因为包装类Integer和基本数据类型int比较时,java会自动拆箱装为int,然后进行比较,实际上就变为两个int变量的比较)。。
Integer i = new Integer(100);
int j = 100;
System.out.print(i == j); //true
非new生成的Integer变量和new Integer()生成的变量比较时,结果为false。(因为非new生成的Integer变量指向的是java常量池【对于Integer类来说是IntegerCache类】中的对象【对于 -128~127 来说】,而new Integer()生成的变量指向堆中新建的对象,两者在内存中的地址不同)。
Integer i = new Integer(100);
Integer j = 100;
System.out.print(i == j); //false
对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间 -128到127 之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false。
Integer i = 100;
Integer j = 100;
System.out.print(i == j); //true
Integer i = 128;
Integer j = 128;
System.out.print(i == j); //false
关于自动装箱和自动拆箱,反编译之后:把装箱转换为Integer.valueOf(),把拆箱转换为Integer.intValue()
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);
}
IntegerCache类的源码:
可以看出Integer 的缓存范围默认是-128到127
。当然缓存上限值也是可以根据需要调整的,JVM提供了参数设置-XX:AutoBoxCacheMax=
,这也就解释了上述代码中i1 == i2
结果为true
,而i3 == i4
为false
的根本原因,即在-128到127(包含)之间的数值都是IntegerCache.cache[] 数组
中的同一个Integer对象。
举一反三,这种缓存机制并不只有Integer才有,同样存在于其他一些包装类:
Boolean,缓存了true/false实例
Byte,数值全部被缓存
Short,缓存了-128到127之间到数值
Character,缓存范围'\u0000'到'\u007f'(0到127)
Long,缓存了-128到127之间的数值
/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/
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() {}
}
3)绝对值问题
Integer的界限范围与int类型是一致的,都是 0x7fffffff~0x80000000 。 这两个范围大家经常用,一般不会出现问题。但是,由于补码表示负数的关系,正数总是比负数少一个。作为边界值,这经常会导致问题。例如下面的Math类中代码:
public static int abs(int a) {
return (a < 0) ? -a : a;
}
这里返回结果不全是正数,输入Integer.MIN_VALUE的结果还是Integer.MIN_VALUE,因为没有相应的补码与之对应。所以在使用绝对值的时候还是要小心的,要考虑是否会出现一个Integer.MIN_VALUE的输入,如果有可能,那就需要更大范围的类型(Long)来表示或者单独对它进行处理。Math提供的abs方法并没有考虑这个问题。
4)进制转换
下面的方法是将形参i转成radix进制的数 :
// 代表数字的所有可能的字符
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'
};
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];
// 判断是否为负数,后面i被当成负数来统一处理(负数范围比正数大,不需要额外处理Integer.MIN_VALUE的问题)
boolean negative = (i < 0);
// buf最末尾的索引,从32开始
int charPos = 32;
if (!negative) {
i = -i;
}
// i%radix的余数的绝对值放到buf当前尾部(charPos)位置
while (i <= -radix) {
buf[charPos--] = digits[-(i % radix)];
i = i / radix;
}
buf[charPos] = digits[-i];
if (negative) {
buf[--charPos] = '-';
}
// 返回字符串,从buf的charPos位置开始截取,长度33-charPos,正好是最后一个位置,索引下标为32
return new String(buf, charPos, (33 - charPos));
}
快速的十进制转换方法:
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);
}
static void getChars(int i, int index, char[] buf) {
int q, r; // r为余数,就是每次被插入到buf的数
int charPos = index;
char sign = 0;
if (i < 0) {
sign = '-';
i = -i;
}
// Generate two digits per iteration
// 每次迭代向buf插入2个数字,即i的最后两位,目的应该是加快迭代速度
while (i >= 65536) {
q = i / 100;
// really: r = i - (q * 100);
// i - q * 100 得到的r就是i的末尾2位数,本质是i%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 (;;) {
// 这里本质就是i/10
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;
}
}
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',
} ;
(1) ALU执行乘法和移位运算的速度快过除法的运算速度。
(2)52429,看到这个数字,联想到524288也就是2^19。q = (i * 52429) >>> (16+3);
实际上这应该是除10的方法,即:
i*52429>>>(19,实际上可以这么写:i*52429/524288,而52429/524288≈0.1000003
。
而我们知道>>>的速度是快于除法的,所以只是java的优化。
那么为什么是2^19呢?稍微列式便能得出,这么计算的话:
103/1024≈0.1006
205/2048≈0.100098
……
52429/524288≈0.1000003
发现2^19精度最高啊。
那么选2^20行吗?
65536=2^16,52429<65536,所以i * 52429 < 2^32,不会溢出 。那么选2^20会溢出。