Integer
- Integer是int的包装类而int是一种基本数据类型。
- Integer是面向对象的,所以必须实例化。
- Integer是对象的引用。int则是存储数据。
类图
1.pngpublic final class Integer extends Number implements Comparable<Integer> {
//
}
-
final
修饰 Integer类没有子类,类中方法默认都是final
(final
方法不能被子类覆盖) -
Integer
继承了Number
类则可使用Number
类中方法 -
Integer
实现了Comparable
接口,所以实现了compareTo
方法。
属性
private属性
//真正存储int值
private final int value;
//序列化相关,Integer实现了 Serializable
@Native private static final long serialVersionUID = 1360826667806852920L;
public属性
//int 最小值
@Native public static final int MIN_VALUE = 0x80000000;
//int 最大值
@Native public static final int MAX_VALUE = 0x7fffffff;
//int
public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
//int bit 位数
@Native public static final int SIZE = 32;
//int byte 位数
public static final int BYTES = SIZE / Byte.SIZE;
构造方法
public Integer(int value) {
this.value = value;
}
//根据string参数构造新Integer对象
public Integer(String s) throws NumberFormatException {
// 10 string转int默认为10进制
this.value = parseInt(s, 10);
}
常见方法
parseInt()
返回一个int基本数据类型
//返回一个十进制的int
public static int parseInt(String s) throws NumberFormatException {
return parseInt(s,10);
}
//返回一个指定进制的int
//该方法会抛出NumberFormatException
// 1. 字符串参数为null
// 2. radix 小于 Character.MIN_RADIX 或者大于 Character.MAX_RADIX
// 3. 字符串不是int类型数据
// 4. 指定进制无法表达字符串
public static int parseInt(String s, int radix) throws NumberFormatException{
}
valueOf()
返回一个
Integer
对象
// 返回一个十进制Integer
public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}
// 返回一个指定进制Integer
public static Integer valueOf(String s, int radix) throws NumberFormatException {
// parseInt()
return Integer.valueOf(parseInt(s,radix));
}
// 内部类 Integer 缓存
public static Integer valueOf(int i) {
// 如果 i 在 IntegerCache 之间,则返回缓存中取出。
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// 默认最大缓存值
int h = 127;
// 读取设置的最大缓存值
String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
// 设置最大值小于127 则最大值为默认值 127
// 设置最大值为Integer.MAX_VALUE 则最大值为 Integer.MAX_VALUE - 128 - 1
i = Math.max(i, 127);
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// 传入的数值不能解析为int,忽略。最大值为默认值 127
}
}
high = h;
// 初始化缓存数组,长度为 127 + 128 + 1
cache = new Integer[(high - low) + 1];
//循环初始化 Integer 对象,并放入缓存数组
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// assert 断言关键字
assert IntegerCache.high >= 127;
}
// 空构造
private IntegerCache() {}
}
valueOf(String s)
与valueOf(String s, int radix)
这两个将字符串转换为Integer对象的方法实现很简单。主要是涉及到缓存内部类的`方法。
Integer a = 10; //this is autoboxing Integer b = Integer.valueOf(10); //under the hood
当程序使用第一次使用
Integer.valueOf()
是则会缓存 -127 到 128 到IntegerCache.cache数组中(缓存的是Integer对象)。注意:构造函数不会使用缓存。
Integer a = 10;
自动装箱编译后Integer b = Integer.valueOf(10);
所以当初始化Integer对象时优先使用
Integer a = 10;
设置最大缓存值方式
-Djava.lang.Integer.IntegerCache.high=1000
-XX:AutoBoxCacheMax=1000
例子
public static void main(String[] args) {
Integer integer1 = 100; // 无缓存,Integer.valueOf(100); new Integer() 放入缓存。
Integer integer2 = 100; // 缓存中读取。同一个Integer对象
Integer integer3 = new Integer(100); // 构造函数不会使用缓存
if(integer1 == integer2){
System.out.println("integer1 == integer2");
}else{
System.out.println("integer1 != integer2");
}
if(integer1 == integer3){
System.out.println("integer1 == integer3");
}else{
System.out.println("构造函数不会使用缓存");
System.out.println("integer1 != integer3");
}
if(integer2 == integer3){
System.out.println("integer2 == integer3");
}else {
System.out.println("构造函数不会使用缓存");
System.out.println("integer2 != integer3");
}
Integer integer5 = 300; // 缓存默认缓存 -127 到 128
Integer integer6 = 300; // 超出缓存
if(integer5 == integer6){
System.out.println("integer5 == integer6");
}else{
System.out.println("integer5 != integer6");
}
}
IntegerCache1.png
IntegerCache2.png
decode()
//接受十进制、十六进制、八进制字符串,返回Integer对象
//通过截取字符串获取进制。然后调用valueOf()
public static Integer decode(String nm) throws NumberFormatException {}
最终调用
valueOf()
方法,故而使用缓存。
getInteger()
// 根据key读取系统属性值。并转为Integer对象
public static Integer getInteger(String nm) {
return getInteger(nm, null);
}
// 如果系统属值不存在则返回默认值 val
public static Integer getInteger(String nm, int val) {
Integer result = getInteger(nm, null);
return (result == null) ? Integer.valueOf(val) : result;
}
public static Integer getInteger(String nm, Integer val) {
String v = null;
try {
//读取系统属性
v = System.getProperty(nm);
} catch (IllegalArgumentException | NullPointerException e) {
}
//系统属性不存在则返回 val
if (v != null) {
try {
return Integer.decode(v);
} catch (NumberFormatException e) {
}
}
return val;
}
最终调用
valueOf()
,故而使用缓存。
toString()
public static String toString(int i) !
//i为最小值直接返回
if (i == Integer.MIN_VALUE)
return "-2147483648";
// 返回整数 i 位数
// ① 如果 i 为负数 则转为正整数。前方代码 i 为最小值是转为正整数会溢出。
// ② 假设 i 等于 10 则 9 < x < 99 。i 循环到 1 ,返回 i + 1 ,10 为2位数。
// ③ 假设 i 等于 -10 ,+1 是标示负号。-10 为3位数
// 设计真精妙啊
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
// 创建一个位数长度的char数组
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
}
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE };
// ② 假设 i 等于 10 则 9 < x < 99 。i 循环到 1 ,返回 i + 1 ,x 位数 2 。
static int stringSize(int x) {
// i ++ 进行无限循环
for (int i=0; ; i++)
if (x <= sizeTable[i])
return i+1;
}
// i 参数,index i 位数,buf index 长度的char数组
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 大于等于 65536 时,每循环一次将 i 最后两位存到 buf 数组中
while (i >= 65536) {
// 除法 假如 i 为 65536 q = 655
q = i / 100;
// 相当于 r = i - (q * 100);
// r = 36
r = i - ((q << 6) + (q << 5) + (q << 2));
//将i设置为取出 最后两位的数字
i = q;
//从数组中获取两位char数值存入buf
buf [--charPos] = DigitOnes[r];
buf [--charPos] = DigitTens[r];
}
// Fall thru to fast mode for smaller numbers
// 当 i 小于 65536 时 循环剩余位 存到 buf 数组 中
// 以上代码将 65536 最后两位存入 buf 后,i = 655
for (;;) {
// 相当于 q = i / 10。此时 q = 65
q = (i * 52429) >>> (16+3);
// 相当于 r = i-(q*10) 。此时 r = 5
r = i - ((q << 3) + (q << 1));
// 将 i 最后一位存入 buf
buf [--charPos] = digits [r];
// 设置 i 为剩余 数字,然后下次循序
i = q;
// i == 0 循环结束,将所有数字拆分存入 buf 中
if (i == 0) break;
}
if (sign != 0) {
//存入负号
buf [--charPos] = sign;
}
// 36 位是 3
// 36 / 10 结果是 3
final static char [] DigitTens = {
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',// 0 - 9
'1', '1', '1', '1', '1', '1', '1', '1', '1', '1',// 10 - 19
'2', '2', '2', '2', '2', '2', '2', '2', '2', '2',// 20 - 29
'3', '3', '3', '3', '3', '3', '3', '3', '3', '3',// 30 - 39
'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',
} ;
// 36 位 取出是 6。
// 36 % 10 余数 6
final static char [] DigitOnes = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',// 0 - 9
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',// 10 - 19
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',// 20 - 29
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',// 30 - 39
'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',
} ;
}
代码上方基本上每一步的注释都有写,debug几次就好了。
int i = 65536;
int q = i / 100;
int r = i - ((q << 6) + (q << 5) + (q << 2));
System.out.println(i);
System.out.println(r);
System.out.println("r = "+ i % 100);
上方代码是从
getChars()
当i >= 65536
后的一段代码,发现使用了众多的位运算得到的结果其实和除法求余是一样的。使用位运算的原因就是要比直接乘除==效率要高==
其他基本类型
Byte
基本和Integer大同小异。
- 同样是
final
修饰 - 继承了
Number
实现了Comparable
parseByte()
public static byte parseByte(String s, int radix) throws NumberFormatException {
//将字符串转为 int
int i = Integer.parseInt(s, radix);
// 如果超出 byte 范围 抛出异常
if (i < MIN_VALUE || i > MAX_VALUE)
throw new NumberFormatException(
"Value out of range. Value:\"" + s + "\" Radix:" + radix);
// 向下转换
return (byte)i;
}
valueOf()
public static Byte valueOf(byte b) {
final int offset = 128;
//同样是从内部缓存类中读取
return ByteCache.cache[(int)b + offset];
}
private static class ByteCache {
private ByteCache(){}
static final Byte cache[] = new Byte[-(-128) + 127 + 1];
// 默认缓存 -128 到 127 数字
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Byte((byte)(i - 128));
}
}
Short
参考Byte和Integer
Long
参考Byte和Integer
网友评论