java源码学习(二)Integer
Integer类包含了一个原始基本类型int。Integer属性中就一个属性,它的类型就是int。
此外,这个类还提供了几个把int转成String和把String转成int的方法,同样也提供了其它跟int相关处理的常量和方法。
一、定义
public final class Integer extends Number implements Comparable<Integer>{}
从该类的声明中我们可以看出Integer是final类型的,表示该类不能被继承,同时该类继承了Number类;
并实现了接口 Comparable。
Number类如下:
public abstract class Number implements java.io.Serializable {
public abstract int intValue();
public abstract long longValue();
public abstract float floatValue();
public abstract double doubleValue();
public byte byteValue() {
return (byte)intValue();
}
public short shortValue() {
return (short)intValue();
}
private static final long serialVersionUID = -8742448824652078965L;
}
Integer继承了Number类,所以该类可以调用longValue、floatValue、doubleValue等系列方法返回对应的类型的值。
二、属性
1. 私有属性
private final int value;
private static final long serialVersionUID = 1360826667806852920L;
value属性就是Integer对象中真正保存int值的
2. 其它属性
public static final int MIN_VALUE = 0x80000000;
public static final int MAX_VALUE = 0x7fffffff;
public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
public static final int SIZE = 32;
public static final int BYTES = SIZE / Byte.SIZE;
定义静态常量,Integer的最小值(-231),最大值(231-1)
TYPE int的Class实例
SIZE 用来以二进制补码形式表示 int 值的比特位数
BYTES 用来以二进制补码形式表示 int 值的字节数。1.8以后才有
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'
};
数值表示成字符串,所要用到的所有字符,这边就能看到最多能表示成36进制
三、方法
1. 构造方法和valueOf方法
Integer提供了两个构造方法:
//构造一个新分配的 Integer 对象,它表示指定的 int 值。
public Integer(int value) {
this.value = value;
}
//构造一个新分配的 Integer 对象,它表示 String 参数所指示的 int 值。
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
首先看一段代码反编译前后对比:
public class IntegerTest {
public static void main(String[] args) {
Integer i = new Integer(10);
i = 5;
}
}
public class IntegerTest
{
public IntegerTest()
{
}
public static void main(String args[])
{
Integer i = new Integer(10);
i = Integer.valueOf(5);
}
}
我们来看看valueOf方法
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
以上是valueOf方法的实现细节。通常情况下,IntegerCache.low=-128,IntegerCache.high=127(除非显示声明java.lang.Integer.IntegerCache.high的值),Integer中有一段动态代码块,该部分内容会在Integer类被加载的时候就执行。
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;
}
也就是说,当Integer被加载时,就新建了-128到127的所有数字并存放在Integer数组cache中。
再回到valueOf代码,可以得出结论。当调用valueOf方法(包括后面会提到的重载的参数类型包含String的valueOf方法)时,如果参数的值在-127到128之间,则直接从缓存中返回一个已经存在的对象。如果参数的值不在这个范围内,则new一个Integer对象返回。
所以,当把一个int变量转成Integer的时候(或者新建一个Integer的时候),建议使用valueOf方法来代替构造函数。或者直接使用Integer i = 100;编译器会转成Integer s = Integer.valueOf(10000);
2. 转字符串
首先看一下,转字符串都有哪些方法:
String toString()
static String toString(int i)
static String toString(int i, int radix)
static String toBinaryString(int i)
static String toHexString(int i)
static String toOctalString(int i)
static String toUnsignedString(int i)
static String toUnsignedString(int i, int radix)
public String toString() {
return toString(value);
}
我们看toString(int i)方法
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);
}
如果i 是Integer.MIN_VALUE,也就是整型的最小值,直接返回"-2147483648",但为什么需要这个判断呢?
由于下面
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
我们看stringSize方法
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;
}
此方法实现获取一个正整数的位数,利用sizeTable(定义位数所对应的最大值),循环依次比较,小于当前位数的最大值,则该整数的位数就是当前sizeTable下标+1
举个例子,若x=2016,因为x大于9,99,999,小于9999,此时9999 所在的sizeTable下表为3,故最后返回4
局部性原理之空间局部性:sizeTable为数组,存储在相邻的位置,cpu一次加载一个块数据数据到cache中(多个数组数据),此后访问sizeTable 不需要访问内存。基于范围的查找,是很实用的设计技术。
然后所有整数的字符长度就可以算出来了,int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);,负数就算整数去正的字符长度+1,加上的是-,也就是有一位存的是负号
stringSize(-i) -i进行转换是,若i=Integer.MIN_VALUE=-2147483648,则-i=2147483648,而整数最大值为2147483647,则转的时候无法赋值,这就解释了为什么要加那个判断
Integer result = -(Integer.MIN_VALUE);程序运行结果为result = -2147483648.
再看getChars(i, size, buf);:
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
// 每次循环过后,都会将i中的走后两位保存到字符数组buf中的最后两位中,读者可以将数字i设置为12345678测试一下,
//第一次循环结束之后,buf[7] = 8,buf[6]=7。第二次循环结束之后,buf[5] = 6,buf[4] = 5。
while (i >= 65536) {
q = i / 100;
// really: r = i - (q * 100);
r = i - ((q << 6) + (q << 5) + (q << 2));
i = q;
//取DigitOnes[r]的目的其实取数字r%10的结果
buf [--charPos] = DigitOnes[r];
//取DigitTens[r]的目的其实是取数字r/10的结果
buf [--charPos] = DigitTens[r];
}
// Fall thru to fast mode for smaller numbers
// assert(i <= 65536, i);
//循环将其他数字存入字符数组中空余位置
for (;;) {
//这里其实就是除以10。取数52429和16+3的原因在后文分析。
q = (i * 52429) >>> (16+3);
r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
//将数字i的最后一位存入字符数组,
//还是12345678那个例子,这个for循环第一次结束后,buf[3]=4。
buf [--charPos] = digits [r];
i = q;
//for循环结束后,buf内容为“12345678”;
if (i == 0) break;
}
if (sign != 0) {
buf [--charPos] = sign;
}
}
//100以下的数,DigitTens十位数上的数字,DigitOnes为个位数的数字,如86 =DigitTens[86]+ DigitOnes[86] = '8' + '6' = 86
//100以内的数字除以10的结果(取整)
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',
} ;
//100以内的数字对10取模的结果
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',
} ;
// really: r = i - (q * 100);
r = i - ((q << 6) + (q << 5) + (q << 2));
r= i - (q * (26 + 25 + 22)) = i - (q * 100);
为什么小于65536,用下面的方法速度比较快?
移位的效率比直接乘除的效率要高
乘法的效率比除法的效率要高
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;
}
q = (i * 52429) >>> (16+3) = (i * 52429) / 524288; 那么就相当于 q = i * 0.1= i /10,这样通过乘法和向右以为的组合的形式代替了除法,能提高效率。
再来回答上面两个问题中,部分一和部分二中最大的区别就是部分一代码使用了除法,第二部分只使用了乘法和移位。因为乘法和移位的效率都要比除法高,所以第二部分单独使用了乘法加移位的方式来提高效率。那么为什么不都使用乘法加移位的形式呢?为什么大于num1(65536)的数字要使用除法呢?原因是int型变量最大不能超过(2^31-1)。如果使用一个太大的数字进行乘法加移位运算很容易导致溢出。那么为什么是65536这个数字呢?第二阶段用到的乘法的数字和移位的位数又是怎么来的呢?
使用num1,num2,num3三个变量代替源代码中的数字,便于后面分析使用num1=65536 num2=52429 num3=16+3=19
既然我们要使用q = (i * num2) >>> (num3);的形式使用乘法和移位代替除法,那么n和m就要有这样的关系:
num2= (2^num3 /10 +1)
只有这样才能保证(i * num2) >>> (num3)结果接近于0.1。
我们看下数据:
2^10=1024, 103/1024=0.1005859375
2^11=2048, 205/2048=0.10009765625
2^12=4096, 410/4096=0.10009765625
2^13=8192, 820/8192=0.10009765625
2^14=16384, 1639/16384=0.10003662109375
2^15=32768, 3277/32768=0.100006103515625
2^16=65536, 6554/65536=0.100006103515625
2^17=131072, 13108/131072=0.100006103515625
2^18=262144, 26215/262144=0.10000228881835938
2^19=524288, 52429/524288=0.10000038146972656
2^20=1048576, 104858/1048576=0.1000003815
2^21=2097152, 209716/2097152 = 0.1000003815
2^22= 4194304, 419431/4194304= 0.1000001431
超过22的数字我就不列举了,因为如果num3越大,就会要求i比较小,因为必须保证(i * num2) >>> (num3)的过程不会因为溢出而导致数据不准确。那么是怎么敲定num1=65536,num2= 524288, num3=19的呢? 这三个数字之间是有这样一个操作的:
(num1* num2)>>> num3
因为要保证该操作不能因为溢出导致数据不准确,所以num1和num2就相互约束。两个数的乘积是有一定范围的,不成超过这个范围,所以,num1增大,num2就要随之减小。
觉得有以下几个原因:
52429/524288=0.10000038146972656精度足够高
下一个精度较高的m和n的组合是419431和22。231/222 = 2^9 = 512。512这个数字实在是太小了。65536正好是2^16,一个整数占4个字节。65536正好占了2个字节,选定这样一个数字有利于CPU访问数据。
不知道有没有人发现,其实65536* 52429是超过了int的最大值的,一旦超过就要溢出,那么为什么还能保证(num1* num2)>>> num3能得到正确的结果呢?
这和>>>有关,因为>>>表示无符号右移,他会在忽略符号位,空位都以0补齐。
一个有符号的整数能表示的范围是-2147483648至2147483647,但是无符号的整数能表示的范围就是0-4,294,967,296(232),所以,只要保证num2*num3的值不超过232次方就可以了。65536是216,52429正好小于216,所以,他们的乘积在无符号向右移位就能保证数字的准确性。
getChars使用了的体系结构知识:
1.乘法比除法高效:q = ( i * 52429) >>> (16+3); => 约等于q0.1,但i52429是整数乘法器,结合位移避免除法。
2.重复利用计算结果:在获取r(i%100)时,充分利用了除法的结果,结合位移避免重复计算。
3.位移比乘法高效:r = i – (( q << 6) + ( q << 5) + ( q << 2)); = >等价于r = i – (q * 100);
4.局部性原理之空间局部性
(1).buf[–charPos] =DigitOnes[r];buf[–charPos] =DigitTens[r];通过查找数组,实现快速访问,避免除法计算
(2).buf [–charPos ] = digits [ r];
return new String(buf, true)
这里用到了一个String中提供的保护类型构造函数,关于此函数请查看String源码分析,该函数比使用其他的构造函数有更好的性能。
再看看转换成任意进制字符串:
public static String toString(int i, int radix) {
//radix 进制数2-32,超出则默认为10进制
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];//33长度,int32个字节,加上负号
boolean negative = (i < 0);
int charPos = 32;
// i 统一变负数
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));
}
上面的方法用于把整形数转成指定radix的 进制数字符串
这边提供了转换为2、8、16进制快捷入口
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);
}
private static String toUnsignedString(int i, int shift) {
char[] buf = new char[32];
int charPos = 32;
int radix = 1 << shift;
int mask = radix - 1;
do {
buf[--charPos] = digits[i & mask];
i >>>= shift;
} while (i != 0);
return new String(buf, charPos, (32 - charPos));
}
位运算
运算符 | 运算符 | 示例 | 说明 |
---|---|---|---|
& | 位与 | x&y | 把x和y按位求与 |
~ | 位非 | ~x | 把x按位求非 |
^ | 位异或 | x^y | 把x和y按位求异或 |
>> | 右移 | x>>y | 把x的各位右移y位 |
<< | 左移 | x<<y | 把x的各位左移y位 |
>>> | 右移 | x>>>y | 把x的各位右移y位,左边填0 |
最后总结一下Integer转string:
所以,一个Integer对象有很多方法能够将值转成String类型。除了上面提到的一系列方法外,一般在要使用String的时候,很多人愿意使用如下形式:
Integer s = new Integer(199);
System.out.println(s + "");
老规矩,反编译看看怎么实现的:
Integer s = new Integer(199);
System.out.println((new StringBuilder()).append(s).append("").toString());
笔者使用JMH进行了测试,结果证明方法效率更高。
3. 字符串转Integer
首先看一下,字符串转Integer都有哪些方法:
public static int parseInt(String s, int radix) throws NumberFormatException
public static int parseInt(String s) throws NumberFormatException
public static int parseUnsignedInt(String s, int radix) throws NumberFormatException
public static int parseUnsignedInt(String s) throws NumberFormatException
public static Integer valueOf(String s, int radix) throws NumberFormatException
public static Integer valueOf(String s) throws NumberFormatException
public static Integer getInteger(String nm)
public static Integer getInteger(String nm, int val)
public static Integer getInteger(String nm, Integer val)
public static Integer decode(String nm) throws NumberFormatException
public static Integer valueOf(String s)
public static Integer valueOf(String s, int radix)
所有将String转成Integer的方法都是基于parseInt方法实现的。简单看一下以上部分方法的调用栈。
getInteger(String nm) ---> getInteger(nm, null);--->Integer.decode()--->Integer.valueOf()--->parseInt()
getInteger的具体实现细节如下:
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;
}
先按照nm作为key从系统配置中取出值,然后调用Integer.decode方法将其转换成整数并返回。
decode
public static Integer decode(String nm) throws NumberFormatException
该方法的作用是将 String 解码为 Integer。接受十进制、十六进制和八进制数字。
根据要解码的 String(mn)的形式转成不同进制的数字。 mn由三部分组成:符号、基数说明符和字符序列。 —0X123中-是符号位,0X是基数说明符(0表示八进制,0x,0X,#表示十六进制,什么都不写则表示十进制),123是数字字符序列。
使用例子举例如下:
Integer DecimalI = Integer.decode("+10");
Integer OctI = Integer.decode("-010");
Integer HexI = Integer.decode("-0x10");
Integer HexI1 = Integer.decode("#10");
System.out.println(DecimalI);
System.out.println(OctI);
System.out.println(HexI);
System.out.println(HexI1);
//10 -8 -16 16
decode方法的具体实现也比较简单,首先就是判断String类型的参数mn是否以(+/—)符号开头。然后再依次判断是否以”0x”、“#”、“0”开头,确定基数说明符的值。然后将字符串mn进行截取,只保留其中纯数字部分。在用截取后的纯数字和基数调用valueOf(String s, int radix)方法并返回其值。
valueOf
public static Integer valueOf(String s) throws NumberFormatException
public static int parseInt(String s, int radix) throws NumberFormatException
返回一个 Integer 对象。如果指定第二个参数radix,将第一个参数解释为用第二个参数指定的基数表示的有符号整数。如果没指定则按照十进制进行处理。
该方法实现非常简单:
public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}
public static Integer valueOf(String s, int radix) throws NumberFormatException {
return Integer.valueOf(parseInt(s,radix));
}
主要用到了两个方法,parseInt(String s, int radix)和valueOf(int i)方法。前面已经讲过valueOf方法会检查参数内容是否在-127到128之间,如果是则直接返回。否则才会新建一个对象。
//字符串转十进制数
public static int parseInt(String s) throws NumberFormatException {
return parseInt(s,10);
}
public static int parseInt(String s, int radix) throws NumberFormatException
使用第二个参数指定的基数(如果没指定,则按照十进制处理),将字符串参数解析为有符号的整数。除了第一个字符可以是用来表示负值的 ASCII 减号 ‘-‘ (‘\u002D’)外,字符串中的字符必须都是指定基数的数字(通过 Character.digit(char, int) 是否返回一个负值确定)。返回得到的整数值。
如果发生以下任意一种情况,则抛出一个 NumberFormatException 类型的异常:
第一个参数为 null 或一个长度为零的字符串。
基数小于 Character.MIN_RADIX 或者大于 Character.MAX_RADIX。
假如字符串的长度超过 1,那么除了第一个字符可以是减号 ‘-‘ (‘u002D’) 外,字符串中存在任意不是由指定基数的数字表示的字符.
字符串表示的值不是 int 类型的值。
实现的一些例子:
- parseInt("0", 10) returns 0
- parseInt("473", 10) returns 473
- parseInt("+42", 10) returns 42
- parseInt("-0", 10) returns 0
- parseInt("-FF", 16) returns -255
- parseInt("1100110", 2) returns 102
- parseInt("2147483647", 10) returns 2147483647
- parseInt("-2147483648", 10) returns -2147483648
- parseInt("2147483648", 10) throws a NumberFormatException
- parseInt("99", 8) throws a NumberFormatException
- parseInt("Kona", 10) throws a NumberFormatException
- parseInt("Kona", 27) returns 411787
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.
*/
// 这个方法映射在IntegerCache初始化之前
// 输入参数的校验,错误抛出异常
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;
}
主要思想其实也很好理解。
“12345”按照十进制转成12345的方法其实就是以下方式: ((1*10)+2)*10)+3)*10+4)*10+5 具体的如何依次取出“12345”中的每一个字符并将起转成不同进制int类型则是Character.digit方法实现的,这里就不深入讲解了。
总结:
上面列举了很多能够将String转成Integer的方法。那么他们之间有哪些区别,又该如何选择呢?
parseInt方法返回的是基本类型int
其他的方法返回的是Integer
valueOf(String)方法会调用valueOf(int)方法。
如果只需要返回一个基本类型,而不需要一个对象,可以直接使用Integert.parseInt("123");
如果需要一个对象,那么建议使用valueOf(),因为该方法可以借助缓存带来的好处。
如果和进制有关,那么就是用decode方法。
如果是从系统配置中取值,那么就是用getInteger
4. 其它方法
public int compareTo(Integer anotherInteger)
public static int compare(int x, int y)
public static int compareUnsigned(int x, int y)
public static long toUnsignedLong(int x) jdk1.8
public static int divideUnsigned(int dividend, int divisor) jdk1.8
public static int remainderUnsigned(int dividend, int divisor) jdk1.8
public static int sum(int a, int b) jdk1.8
public static int max(int a, int b) jdk1.8
public static int min(int a, int b) jdk1.8
在看是介绍Interger的类定义的时候介绍过,Integer类实现了Comparable接口,所以Integer对象可以和另外一个Integer对象进行比较。
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
代码实现比较简单,就是拿出其中的int类型的value进行比较。
5. 参考资料
http://www.hollischuang.com/archives/1058
java源码学习(二)Integer的更多相关文章
- JDK源码学习笔记——Integer
一.类定义 public final class Integer extends Number implements Comparable<Integer> 二.属性 private fi ...
- Dubbo源码学习(二)
@Adaptive注解 在上一篇ExtensionLoader的博客中记录了,有两种扩展点,一种是普通的扩展实现,另一种就是自适应的扩展点,即@Adaptive注解的实现类. @Documented ...
- 在IDEA中搭建Java源码学习环境并上传到GitHub上
打开IDEA新建一个项目 创建一个最简单的Java项目即可 在项目命名填写该项目的名称,我这里写的项目名为Java_Source_Study 点击Finished,然后在项目的src目录下新建源码文件 ...
- Java 源码学习系列(三)——Integer
Integer 类在对象中包装了一个基本类型 int 的值.Integer 类型的对象包含一个 int 类型的字段. 此外,该类提供了多个方法,能在 int 类型和 String 类型之间互相转换,还 ...
- Java 源码学习线路————_先JDK工具包集合_再core包,也就是String、StringBuffer等_Java IO类库
http://www.iteye.com/topic/1113732 原则网址 Java源码初接触 如果你进行过一年左右的开发,喜欢用eclipse的debug功能.好了,你现在就有阅读源码的技术基础 ...
- python 协程库gevent学习--gevent源码学习(二)
在进行gevent源码学习一分析之后,我还对两个比较核心的问题抱有疑问: 1. gevent.Greenlet.join()以及他的list版本joinall()的原理和使用. 2. 关于在使用mon ...
- Vue源码学习二 ———— Vue原型对象包装
Vue原型对象的包装 在Vue官网直接通过 script 标签导入的 Vue包是 umd模块的形式.在使用前都通过 new Vue({}).记录一下 Vue构造函数的包装. 在 src/core/in ...
- 以太坊 layer2: optimism 源码学习(二) 提现原理
作者:林冠宏 / 指尖下的幽灵.转载者,请: 务必标明出处. 掘金:https://juejin.im/user/1785262612681997 博客:http://www.cnblogs.com/ ...
- java集合类源码学习二
我们查看Collection接口的hierarchy时候,可以看到AbstractCollection<E>这样一个抽象类,它实现了Collection接口的部分方法,Collection ...
随机推荐
- POJ1012-Joseph数学
题目链接:http://poj.org/problem?id=1012 题目大意: 约瑟夫环的一个扩展,2*k个人围一圈,前k个是好人,后k个是坏人.报到m的人就要死掉,然后重新开始报数.要求的是最小 ...
- 使用Github Page鼓励自己每日编程
动机 三天不练手生,编程的基础训练本身是很枯燥的,需要很多的认真与坚持.无论是Debug的经验,语法规则的记忆,还是各类基础的算法运用,都需要持之以恒的认真.Github的"打卡" ...
- 【转】纯手工玩转 Nginx 日志
Nginx 日志对于大部分人来说是个未被发掘的宝藏,总结之前做某日志分析系统的经验,和大家分享一下 Nginx 日志的纯手工分析方式. Nginx 日志相关配置有 2 个地方:access_log 和 ...
- PHP中的运算符
一.算术运算符 运算符 名称 描述 实例 结果 x + y 加 x 和 y 的和 2 + 2 4 x - y 减 x 和 y 的差 5 - 2 3 x * y 乘 x 和 y 的积 5 * 2 1 ...
- SQLiteDatabase的使用
新建DBHeler.JAVA package com.hixin.db; import java.util.ArrayList; import java.util.HashMap; import co ...
- python socket+tcp三次握手四次撒手学习+wireshark抓包
Python代码: server: #!/usr/bin/python # -*- coding: UTF-8 -*- # 文件名:server.py import socket # 导入 socke ...
- 一个IT人员实用的工具:Tmux
1.Tmux安装 tmux下载地址: http://sourceforge.net/projects/tmux/files/tmux/tmux-1.6/tmux-1.6.tar.gz/download ...
- RavenDB FS 安装使用 介绍
前言 最近项目因为要存储图片和文件,折腾了RavenDB,使用RavenDB的FS系统统一管理图片和文件. 安装 RavenDB 的FS文件系统,需要用到windows的远程差分压缩功能: 安装好之后 ...
- Webdriver+Java实现使用cookie跳过登录
Webdriver+Java实现使用cookie跳过登录 Webdriver模拟登录过程中很有可能遇到验证码,最近认真学习了下如何使用cookie直接跳过登录过程. 一.cookie的定义 来源百 ...
- intersect for multiple vectors in R
Say you have a <- c(1,3,5,7,9) b <- c(3,6,8,9,10) c <- c(2,3,4,5,7,9) A straightforward way ...