int 是 Java 八大原始类型之一,是 Java 语言中为数不多不是对象的东西,Integer 是 int 的包装类,里面使用了一个 int 类型的变量来存储数据,提供了一些整数之间的常用操作,常规性的介绍就这么一点,程序员不喜欢说,程序员就喜欢源码,我们还是来看源码吧
*
@author
Lee
Boynton
*
@author
Arthur
van
Hoff
*
@author
Josh
Bloch
*
@author
Joseph
D
.
Darcy
*
@since
JDK1
.
0
*/
public
final
class
Integer
extends
Number
implements
Comparable
<
Integer
>
{
/**
* A constant holding the minimum value an {@code int} can
* have, -2<sup>31</sup>.
*/
@Native
public
static
final
int
MIN_VALUE
=
0x80000000
;
/**
* A constant holding the maximum value an {@code int} can
* have, 2<sup>31</sup>-1.
*/
@Native
public
static
final
int
MAX_VALUE
=
0x7fffffff
;
/**
* The value of the {@code Integer}.
*
* @serial
*/
private
final
int
value
;
/**
* Constructs a newly allocated {@code Integer} object that
* represents the specified {@code int} value.
*
* @param value the value to be represented by the
* {@code Integer} object.
*/
public
Integer
(
int
value
)
{
this
.
value
=
value
;
}
/**
* Constructs a newly allocated {@code Integer} object that
* represents the {@code int} value indicated by the
* {@code String} parameter. The string is converted to an
* {@code int} value in exactly the manner used by the
* {@code parseInt} method for radix 10.
*
* @param s the {@code String} to be converted to an
* {@code Integer}.
* @exception NumberFormatException if the {@code String} does not
* contain a parsable integer.
* @see java.lang.Integer#parseInt(java.lang.String, int)
*/
public
Integer
(
String
s
)
throws
NumberFormatException
{
this
.
value
=
parseInt
(
s
,
10
);
}
上面这段源码是我截取出来的,在 Integer 类中,这些代码不是连在一起的,把他们放在一起,那是因为我想说明点事情,我们仔细看看这段代码,Integer 类是被 final ,这说明了什么?用于存放变量的 value 也被 private final 修饰,这又说明了什么?看着这些是不是有点熟悉呢? 没错,String 对象也是这样的,这说明 Integer 对象也是不可变的,所以以后如果被问到 Integer 对象是不是不可变对象时,记得回答是喔。为什么 Integer 对象也会设计成不可变对象呢?其实我也不知道,我没有从文档中找到答案,但是在杨晓峰老师的文章中看到过有关说明,杨晓峰老师说 Integer 类设计成不可变跟 getInteger() 方法有关系,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
;
}
getInteger() 方法是用来获取系统属性的,我们通过属性来设置服务器的某个服务器的端口,如果 Integer 可变的话,那么我们就能够轻易的改变这个属性的值,这会使得我们的产品存在安全风险。
上面我们我们简单的聊了一下 Integer 类的实现,聊到 int 与 Integer,自然就少不了自动装箱和自动拆箱。
1、自动装箱、拆箱
自动装箱和拆箱是从 JDK 1.5 开始引进的功能,它是一种语法糖,Java 可以根据上下文,自动的在原始类型和包装类型中进行转换,简单的来说就是 Java 平台保证了不同的写法通过编译之后会产生相同的字节码,保证了运行时是等价的。自动装箱和拆箱极大地简化了相关编程。
自动装箱:将原始类型转化为包装类型的过程
比如将 int 类型转换成 integer 类型,这就是原始类型到包装类型的转变,在编译的时候,编译器就会帮我们做自动转换,这个过程对我们程序员来说是无感知的,例如这段给 Integer 对象赋值的代码:
Integer
x
=
3000
;
这段代码经过编译器之后,会转换成下面这段代码:
Integer
x
=
Integer
.
valueOf
(
3000
);
这就是自动装箱过程,这个过程你是不知道的,所以它才叫自动装箱,在自动装箱的过程中使用到了 valueOf() 方法,来看看 JDK 中这个方法的源码:
public
static
Integer
valueOf
(
int
i
)
{
if
(
i
>=
IntegerCache
.
low
&&
i
<=
IntegerCache
.
high
)
return
IntegerCache
.
cache
[
i
+
(-
IntegerCache
.
low
)];
return
new
Integer
(
i
);
}
这个方法里,前面先进行了一个缓存判断,如果你不知道的话,先忽略掉它,最后返回了 new Integer(i) 对象引用,这个方法就是帮你去调用了 Integer 类的构造器。这就是自动装箱。
自动拆箱:将包装类型转换成原始类型的过程
将 Integer 类型转换为 Int 类型,这是一个包装类型转成成原始类型的过程,在这个过程中就会涉及到自动拆箱。来看看这段代码(这是一段很操蛋的代码,实际中应该没人这样写):
Integer
mm
=
1000
;
int
mmm
=
mm
;
在编译的时候,这段代码会被编译器编译成下面这段代码:
Integer
mm
=
Integer
.
valueOf
(
1000
);
int
mmm
=
mm
.
intValue
();
主要看 intmmm=mm.intValue();这行代码,这行代码跟我们写的不一样了,使用到了一个 intValue() 方法,来看看 Integer 类中 intValue() 方法的源码:
/**
* Returns the value of this {@code Integer} as an
* {@code int}.
*/
public
int
intValue
()
{
return
value
;
}
这个方法的作用就是把 Integer 对象中用来存储值的 value 变量返回了,这就是自动拆箱,好了,关于自动装箱和自动拆箱我们都了解了,还记得自动装箱过程中涉及到的缓存吗?接下来我们一起了解一下。
2、Integer 缓存策略
在自动装箱的 valueOf() 方法中,我们看到了有一个缓存判断的操作,是的,Integer 类中有缓存池,会将使用频繁的值缓存起来,以便提高系统的使用性能,在自动装箱的过程中,会先判断该值是否存在缓存池中,如果存在直接从缓存池中取出引用返回,如果不存在则调用构造函数构造对象。缓存是自动装箱操作独享的,直接通过构造函数构造出来的 Integer 对象即使值在缓存范围内,也不会使用到缓存池。在 Integer 类中,使用了一个内部类来实现缓存,这个内部类叫做 IntegerCache,IntegerCache 类的源代码如下:
/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/
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
;
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
;
}
private
IntegerCache
()
{}
}
从源码和 Java 注释中我们可以看出 IntegerCache 的缓存默认值范围 -128 ~ 127 。但是我们也可以在启动时通过 JVM 命令来设置缓存范围的最大值,只需要在启动时添加 -XX:AutoBoxCacheMax= 参数就可以了,但是记得这个 size 可不要乱设置,需要全方位考虑,比如你设置成 10 万,那么这 10 万个数都会在启动刚启动时就添加到内存中,想想这会占用你多少内存?这样做就得不偿失了,Java 公司设置成 -128 ~ 127 是有道理的,发现大部分人使用的值都在 -128 ~ 127 之间,这些值占用的内存比较少,性能上比通过构造函数构造对象要好不少。如何你使用的 Integer 的值在缓存范围的话,就用 Integer i = value 的形式构建对象,如果你的值不在缓存范围内,则使用 Integer i = new Integer(value) 的形式构建 Integer 对象,避免自动装箱的过程。最后我们来看一下 Integer 对象比较常用的方法 parseInt 方法
3、parseInt() 方法
parseInt() 方法的作用是用来将整数型的字符串转换成整数,parseInt 方法需要和 valueOf 方法区分开来,有不少人会问这两方法有什么区别,最后都会返回 int 类型,都能将整数型的字符串转换成整数型,比如这段代码
System
.
out
.
println
(
Integer
.
parseInt
(
"+12"
));
System
.
out
.
println
(
Integer
.
valueOf
(
"+12"
));
最后都会输出 12 ,输出的结果相同是因为 valueOf 方法使用中会调用 parseInt 方法将整数型字符转换为整数,并且会在内存中创建一个值为 12 的 Integer 对象,然后返回这个对象引用。而 parseInt 方法只会帮你将整数型字符转换为整数,不会额外的创建对象。所以它们两得到相同的结果纯属是巧合。一起瞅瞅 parseInt 方法的源代码:
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.
*/
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
;
}
在调用 parseInt 方法时,我们可以传入一个 radix 变量,用来告诉它使用什么进制来进行转换,默认使用的是十进制。
java培训学校:http://www.baizhiedu.com/java2019