内容简介:Integer的基本实现Integer的使用Integer封装的操作
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=<size>} 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=<size>来设置其大小
数组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)
3i + (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之间转换的精彩实现,有时间会记录。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Blockchain Basics
Daniel Drescher / Apress / 2017-3-16 / USD 20.99
In 25 concise steps, you will learn the basics of blockchain technology. No mathematical formulas, program code, or computer science jargon are used. No previous knowledge in computer science, mathema......一起来看看 《Blockchain Basics》 这本书的介绍吧!