一、前言
Integer
类是我们经常用到的一个基础类,学习其底层结构有助于我们在项目中更加得心应手的使用他,并且能够有效避免Integer
所遇到的坑。这篇博客主要是介绍Integer
经常使用的几个方法其源码是怎么做的,而且针对Integer
的一些变量进行解释,这会有助于我们读懂Integer
的源码。
二、源码解析
继承了哪些类
由上图可知Integer
继承了Number
抽象类和实现了Comparable
接口。
变量说明
// 0x80000000 转换为十进制值为 -2^31,它表示 int 类型能够表示的最小值
@Native
public static final int MIN_VALUE = 0x80000000;
// 0x7fffffff 转换为十进制值为 2^31-1,它表示 int 类型能够表示的最大值
@Native
public static final int MAX_VALUE = 0x7fffffff;
// 表示基本类型 int 的 Class 实例
@SuppressWarnings("unchecked")
public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
// 用于将数字表示为字符串的所有可能字符
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'
};
// 用在判断一个int类型数字对应字符串的长度,非常巧妙。
final static int[] sizeTable = {9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE};
// 保存Integer类中的真实基本数据类型的值
private final int value;
构造方法
Integer
类的构造方法只有两个,如下所示:
public Integer(int value) {
this.value = value;
}
/**
* 以字符串为参数的构造方法
* 默认返回十进制的值
*
* @param s
* @throws NumberFormatException
*/
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
常用方法
① String toString(int i, int radix)
方法:转化对应进制的数字为十进制。
/**
* 转化对应进制的数字为十进制
*
* @param i 目标数字
* @param radix 对应的进制数
* @return
*/
public static String toString(int i, int radix) {
// 如果进制数小于2进制或者大于36进制,则改用十进制。
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
radix = 10;
// 如果是十进制,用最快的版本
if (radix == 10) {
return toString(i);
}
// 创建一个33位的字符数组,当负数时:1位符号位+32位数字;正数时,32位数字。
char buf[] = new char[33];
boolean negative = (i < 0);
int charPos = 32;
// 将正数转为负数进行运算,防止负数转为正数的溢出情况,即i一直为负数
if (!negative) {
i = -i;
}
// 此循环则是根据i和radix获取求余的值并且以倒序放到buf数组中
while (i <= -radix) {
buf[charPos--] = digits[-(i % radix)];
i = i / radix;
}
buf[charPos] = digits[-i];
// 若是负数,加减号
if (negative) {
buf[--charPos] = '-';
}
// 返回一个字符串,参数为char数组,起始位置,字符长度
return new String(buf, charPos, (33 - charPos));
}
② toString(int i)
方法:返回当前数字(十进制)的字符串形式。
/**
* 返回当前数字(十进制)的字符串形式
*
* @param i
* @return
*/
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];
// 将数字分成一个个char,保存到buf数组中
getChars(i, size, buf);
// 通过数组buf返回一个字符串,后面的参数share=true应该是没有用的
return new String(buf, true);
}
/**
* 判断一个int类型数字的长度
*
* @param x
* @return
*/
static int stringSize(int x) {
for (int i = 0; ; i++)
if (x <= sizeTable[i])
return i + 1;
}
③ parseInt(String s)
方法:返回指定字符串的一个Integer对象(10进制)。
/**
* 返回指定字符串的一个Integer对象(10进制)
*
* @param s
* @return
* @throws NumberFormatException
*/
public static int parseInt(String s) throws NumberFormatException {
return parseInt(s, 10);
}
/**
* 返回输入字符串的指定进制的正整数
*
* @param s 字符串
* @param radix 指定的进制数
* @return
* @throws NumberFormatException
*/
public static int parseInt(String s, int radix) throws NumberFormatException {
/**
* 警告:此方法可能在VM初始化期间,初始化IntegerCache之前提早调用。必须注意不要使用valueOf方法。
*/
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);
// 如果第一个字符小于0,即有可能为"+" or "-"
if (firstChar < '0') {
//若为第一个字符为"-",则表示字符串要转换的是一个负数
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+') //若不等于“+”,则有可能字符串的第一个字符为其他符号,则此字符串不是一个数值
throw NumberFormatException.forInputString(s);
// len为1的情况则为只有"+"或者"-"符号,也表明字符串不是一个数值
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
multmin = limit / radix;
// 将字符串的数字转为对应进制的数字
while (i < len) {
// 将字符串的数字部分的一个数字(对应进制),通过Character类转为进制的数
digit = Character.digit(s.charAt(i++), radix);
// 若字符串中的某一个字符,在字符串进制下(radix)是无效的,则返回-1
// 此时则抛出异常即可
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;
}
④ valueOf(String s)
方法:将字符串转换为十进制的Integer。
/**
* 将字符串转换为十进制的Integer
*
* @param s
* @return
* @throws NumberFormatException
*/
public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}
/**
* 返回一个表示指定的 int 值的 Integer 实例。
* 如果不需要新的 Integer 实例,则通常应优先使用该方法
* 而不是构造方法 Integer(int),因为该方法可以通过缓存经常请求的值而显著提高空间和时间性能。
*
* @param i
* @return
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
// 直接获得在[low,high]范围内的IntegerCache缓存的Integer对象,不在该范围则重新实例化Integer对象
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
⑤ hashCode()
方法:返回此 Integer 的哈希码。
/**
* 返回此 Integer 的哈希码
*
* @return
*/
@Override
public int hashCode() {
return Integer.hashCode(value);
}
/**
* 返回{@code int}值的哈希码;与{@code Integer.hashCode()}兼容。
*
* @param value
* @return
*/
public static int hashCode(int value) {
return value;
}
⑥ equals(Object obj)
方法:比较此对象与指定对象是否相等。
/**
* 比较此对象与指定对象。当且仅当参数不为 null,
* 并且是一个与该对象包含相同 int 值的 Integer 对象时,结果为 true。
*
* @param obj
* @return
*/
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer) obj).intValue();
}
return false;
}
⑦ getInteger(String nm)
方法:返回系统常量的int值,类似System.getProperty(str)
。
/**
* 返回系统常量的int值,类似System.getProperty(str);
*
* @param nm 属性名,系统常量
* @return
*/
public static Integer getInteger(String nm) {
return getInteger(nm, null);
}
/**
* 返回系统常量的int值,类似System.getProperty(str);
* 如果获取的系统常量值为空,则返回val
*
* @param nm 属性名,系统常量
* @param val 默认值
* @return
*/
public static Integer getInteger(String nm, int val) {
Integer result = getInteger(nm, null);
return (result == null) ? Integer.valueOf(val) : result;
}
/**
* 返回具有指定名称的系统属性的整数值
*
* @param nm 属性名,系统常量
* @param val 默认值
* @return
*/
public static Integer getInteger(String nm, Integer val) {
String v = null;
try {
//获取系统常量对应的值
v = System.getProperty(nm);
} catch (IllegalArgumentException | NullPointerException e) {
}
if (v != null) {
try {
// 如果获取的不为空值,则通过解码函数返回对饮的int值,否则则返回默认值val
return Integer.decode(v);
} catch (NumberFormatException e) {
}
}
return val;
}
⑧ compareTo(Integer anotherInteger)
方法:比较两个Integer
对象的value值大小。
/**
* 比较两个 Integer 对象的value值大小
*
* @param anotherInteger
* @return
*/
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
/**
* 比较两个int类型的值的大小,很巧妙,值得学习
*
* @param x
* @param y
* @return
*/
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
三、总结
Integer类里面很多巧妙的代码非常值得我们去学习,能够读懂这些的话将会对自己的能力有所提升。