15036188778

您所在位置: 首页> 学习课程> java培训学校 | 从 Int 到 Integer 对象,这些内容你知道吗?

java培训学校 | 从 Int 到 Integer 对象,这些内容你知道吗?

发布百知教育 来源:学习课程 2019-10-10

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

 

(

!=

 

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

 

(

>=

 

IntegerCache

.

low 

&&

 i 

<=

 

IntegerCache

.

high

)

        

return

 

IntegerCache

.

cache

[

+

 

(-

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

 

(

==

 

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

 

(

<

 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

上一篇:java培训学校 | Java爬虫遇到需要登录的网站,该怎么办?

下一篇:应届生去公司找个Java程序员的职位需要什么技能?

相关推荐

www.baizhiedu.com

有位老师想和您聊一聊

关闭

立即申请