java if 中integer_Java源码阅读笔记之Integer

  • Post author:
  • Post category:java


Integer的基本实现

Integer的使用

Integer封装的操作

Integer的基本实现

基本描述:

Integer是对原生基本类型int的封装,其定义value来存储值和一些用于描述int的信息

int value;//int

int SIZE = 32;//1位正负标识+31位数据

int BYTES = SIZE / Byte.SIZE;//所占字节

int MIN_VALUE = 0x80000000;//最小值,32个1

int MAX_VALUE = 0x7fffffff;//最大值,0+31个1

构造函数:

允许通过String和int入参来为value赋值,但是两个构造函数都已弃用

通过注释可以看到,推荐通过valueOf()的方法来返回一个Integer

/**

* @deprecated

* It is rarely appropriate to use this constructor. The static factory

* {@link #valueOf(int)} is generally a better choice, as it is

* likely to yield significantly better space and time performance.

*/

@Deprecated(since=”9″)

public Integer(int value) {

this.value = value;

}

/**

* @deprecated

* It is rarely appropriate to use this constructor.

* Use {@link #parseInt(String)} to convert a string to a

* {@code int} primitive, or use {@link #valueOf(String)}

* to convert a string to an {@code Integer} object.

*/

@Deprecated(since=”9″)

public Integer(String s) throws NumberFormatException {

this.value = parseInt(s, 10);

}

使用推荐的方法获取Integer实例和构造方法有何不同?

//———————-int入参——————

@HotSpotIntrinsicCandidate

public static Integer valueOf(int i) {

if (i >= IntegerCache.low && i <= IntegerCache.high)

return IntegerCache.cache[i + (-IntegerCache.low)];

return new Integer(i);

}

//———————-String入参——————

public static Integer valueOf(String s) throws NumberFormatException {

return Integer.valueOf(parseInt(s, 10));

}

//radix表示进制,取值范围为[2, 36]

public static Integer valueOf(String s, int radix) throws NumberFormatException {

return Integer.valueOf(parseInt(s,radix));

}

int入参

如果入参中的int在IntegerCache内部类的Integer cache[]中存在则返回数组中的Integer否则通过构造函数创建(弃用的那个)

String入参

通过parseInt(s,radix)方法解析字符串,返回int值

radix参数表示字符串转换的int值的进制,其取值范围为[2,36]

解析IntegerCache和parseInt的实现

IntegerCache

//The cache is initialized on first usage.

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;

//The size of the cache may be controlled by the {@code -XX:AutoBoxCacheMax=} option.

String integerCacheHighPropValue =

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() {}

}

IntegerCache是一个私有静态内部类该类内部定义了一个数组Integer cache[],数组内的数据由-128起始,默认至127为止(byte的范围)

该数组的最大值可通过在jvm中设置

-XX:AutoBoxCacheMax=来设置其大小

数组cache[128]为0,valueof(int)参数的值符合这个范围都会直接从数组中返回Integer

有意思的是valueof(int)是@HotSpotIntrinsicCandidate的,关于它的描述是这样的:

JDK的源码中,被@HotSpotIntrinsicCandidate标注的方法,在HotSpot中都有一套高效的实现,该高效实现基于CPU指令,运行时,HotSpot维护的高效实现会替代JDK的源码实现,从而获得更高的效率。

估计这就是推荐使用的主要原因吧!

parseInt

public static int parseInt(String s, int radix)

throws NumberFormatException

{

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) {

// Accumulating negatively avoids surprises near MAX_VALUE

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);

}

}

static final 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’

};

字符串转化为int的关键在于digits数组,以16进制为例,用0…9,a…f表示0到15,满16才会进1。也就是超过10进制以后,大于10的数要使用a开始的字母表示,但是字母只有26个,进制又必须从2开始,故进制的取值范围也就定义为[2, 36]

故入参的字符串s也必须符合digits数组中的元素以及额外的只可能存在第一位”+”或者”-”

parseInt的转化逻辑为:

在每次循环中

取出digit,确定进制后转化的int数

通过result *= radix;把上一次循环的数据进一位

通过result -= digit;把当前的数据加入result

然后返回结果,通过:

return negative ? result : -result;

Integer的使用

int a = 5;

Integer w = 6;

Integer test = Integer.valueOf(w);

int testP = Integer.valueOf(a);

转化成对应的字节码,则

int a = 5

0: iconst_5

1: istore_1

直接将自然数压栈

Integer w = 6

2: bipush 6

4: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

7: astore_2

调用Integer的静态方法valueof(6)得到Integer实例

Integer test = Integer.valueOf(w)

8: aload_2

9: invokevirtual #3 // Method java/lang/Integer.intValue:()I

12: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

15: astore_3

获取操作数栈中w的引用,调用intValue返回int值,再通过valueof获取Integer实例

int testP = Integer.valueOf(a)

16: iload_1

17: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

20: invokevirtual #3 // Method java/lang/Integer.intValue:()I

获取操作数栈中的a,调用valueof获取Integer实例,再通过intValue返回int值

由此可知,对于基本类型的封装类,编译器会自动调用其一些方法来实现用户操作的简化!

Integer封装的操作

Object虚函数的实现

父类Number的虚函数实现

字节操作

Object虚函数的实现

public boolean equals(Object obj) {

if (obj instanceof Integer) {

return value == ((Integer)obj).intValue();

}

return false;

}

public static int hashCode(int value) {

return value;

}

public static String toString(int i) {

int size = stringSize(i);

if (COMPACT_STRINGS) {

byte[] buf = new byte[size];

getChars(i, size, buf);

return new String(buf, LATIN1);

} else {

byte[] buf = new byte[size * 2];

StringUTF16.getChars(i, size, buf);

return new String(buf, UTF16);

}

}

equals

通过Integer的intValue获取入参的Integer封装的int值并与value进行==寻址判断

hashCode

hashCode返回的就是一个int值,故直接使用value本身

toString

使用char数组做中转,通过String实例化一个String实例

根据是否开启压缩机制判断使用的是LATIN1还是UTF16

父类Number的虚函数实现

public byte byteValue() {

return (byte)value;

}

public double doubleValue() {

return (double)value;

}

public float floatValue() {

return (float)value;

}

public int intValue() {

return value;

}

public long longValue() {

return (long)value;

}

public short shortValue() {

return (short)value;

}

只是对value进行强转

字节操作

计算int二进制形式左(右)侧有几个0,遇到1就停止计数

计算int二进制形式1的数量

左(右)移二进制形式

按位(字节)置换

计算int二进制形式左(右)侧有几个0,遇到1就停止计数

//左侧

public static int numberOfLeadingZeros(int i) {

// HD, Count leading 0’s

if (i <= 0)

return i == 0 ? 32 : 0;

int n = 31;

if (i >= 1 << 16) { n -= 16; i >>>= 16; }

if (i >= 1 << 8) { n -= 8; i >>>= 8; }

if (i >= 1 << 4) { n -= 4; i >>>= 4; }

if (i >= 1 << 2) { n -= 2; i >>>= 2; }

return n – (i >>> 1);

}

//右侧

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

1 负数1标识,左侧无0,0全为0,直接返回32(int为32位)

2 通过1 << 16判断,判断条件为是否比它大,左边16位是否全为0,决定接下来操作左或右半边

3 再通过i << 8,4,2,1折半再折半计算出不为0的数字的位置,从而得出0的数量

右侧:numberOfTrailingZeros

通过i <<16,不为0则右边有1,再i << 8,4,2,1,判断出右边数起的第一个1,从而计算出0的数量

计算int二进制形式1的数量

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;

}

0x5 = 0101,通过做&运算记录双数位的数据情况

0x3 = 0011,通过做&运算记录后两位的数据情况

0x0f = 0000 1111,通过做&运算记录后四位的数据情况

1 int的二进制形式的可能有 00,01,10,11

先做>>>右移一位再与01做&运算,记录了两位二进制左边数字的1的数量,再用原来的二进制数减去记录的值

如11:11-01=10(11有两个1)

2 经过第一步计算,记录了以两位数为单位的1的数量

把第一步的结果与0011做&运算得到四位二进制结果的后两位计算,0011再与四位二进制结果>>>右移两位计算前两位的结果,再把其相加得到四位数中1的数量

如1011

1011 – 0101 = 0110

0001 + 0010 = 0011(1011有三个1)

3 i + (i >>> 4),i + (i >>> 8),i + (i >>> 16)分别把得到的上一步计算的结果整合计算

计算完成后记录结果的有效位数只有右边八位,32位数一共最多32个1,所以实际的有效位数只有右边6位

左(右)移二进制形式

public static int rotateLeft(int i, int distance) {

return (i << distance) | (i >>> -distance);

}

public static int rotateRight(int i, int distance) {

return (i >>> distance) | (i << -distance);

}

移动

调用<>运算符移动,同时通过 | >>> -distance得到移动消逝的数据,并将其放在补0的位置

-distance表示移动-distance负数的表现形式int截取5位,long截取6位,如-1为32个1,截取5位为1 1111,为31,也就是不算位移,移动的“路程”是32,正好把移出的数据再补回补0的地方

按位(字节)置换

public static int reverseBytes(int i) {

return (i << 24) |

((i & 0xff00) << 8) |

((i >>> 8) & 0xff00) |

(i >>> 24);

}

public static int reverse(int i) {

// HD, Figure 7-1

i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;

i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;

i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;

return reverseBytes(i);

}

按字节置换:reverseBytes

i << 24与i >>> 24做 | 运算得到最左右两边的置换

0xff00二进制形式为1111 1111 0000 0000

正好用来处理中间左八位和右八位的交换,主要是&和移动的先后来实现不同的位的清零

按位置换:reverse

1 使用01来记录两位二进制中的一位,再通过移动记录另一位,做 | 运算的会把两位的二进制数交换位置

2 通过0011来交换四位中的前两位和后两位

3 通过0000 1111来交换前四位和后四位

4 通过前三步实现交换每8位的循序,再通过按字节置换交换全部的顺序

后话

Integer中还有关于

static final byte[] 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’,

} ;

static final byte[] 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’,

} ;

这两个数组的应用和字符和byte之间转换的精彩实现,有时间会记录。



版权声明:本文为weixin_39545895原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。