javaee论坛

普通会员

225648

帖子

355

回复

369

积分

楼主
发表于 2019-11-04 09:16:52 | 查看: 64 | 回复: 0

int是Java八大原始类型之一,是Java语言中为数不多不是对象的东西,Integer是int的包装类,里面使用了一个int类型的变量来存储数据,提供了一些整数之间的常用操作,常规性的介绍就这么一点,程序员不喜欢说,程序员就喜欢源码,我们还是来看源码吧

*@authorLeeBoynton*@authorArthurvanHoff*@authorJoshBloch*@authorJosephD.Darcy*@sinceJDK1.0*/publicfinalclassIntegerextendsNumberimplementsComparable<Integer>{/***Aconstantholdingtheminimumvaluean{@codeint}can*have,-2<sup>31</sup>.*/@NativepublicstaticfinalintMIN_VALUE=0x80000000;/***Aconstantholdingthemaximumvaluean{@codeint}can*have,2<sup>31</sup>-1.*/@NativepublicstaticfinalintMAX_VALUE=0x7fffffff;/***Thevalueofthe{@codeInteger}.**@serial*/privatefinalintvalue;/***Constructsanewlyallocated{@codeInteger}objectthat*representsthespecified{@codeint}value.**@paramvaluethevaluetoberepresentedbythe*{@codeInteger}object.*/publicInteger(intvalue){this.value=value;}/***Constructsanewlyallocated{@codeInteger}objectthat*representsthe{@codeint}valueindicatedbythe*{@codeString}parameter.Thestringisconvertedtoan*{@codeint}valueinexactlythemannerusedbythe*{@codeparseInt}methodforradix10.**@paramsthe{@codeString}tobeconvertedtoan*{@codeInteger}.*@exceptionNumberFormatExceptionifthe{@codeString}doesnot*containaparsableinteger.*@seejava.lang.Integer#parseInt(java.lang.String,int)*/publicInteger(Strings)throwsNumberFormatException{this.value=parseInt(s,10);}

上面这段源码是我截取出来的,在Integer类中,这些代码不是连在一起的,把他们放在一起,那是因为我想说明点事情,我们仔细看看这段代码,Integer类是被final,这说明了什么?用于存放变量的value也被privatefinal修饰,这又说明了什么?看着这些是不是有点熟悉呢?没错,String对象也是这样的,这说明Integer对象也是不可变的,所以以后如果被问到Integer对象是不是不可变对象时,记得回答是喔。为什么Integer对象也会设计成不可变对象呢?其实我也不知道,我没有从文档中找到答案,但是在杨晓峰老师的文章中看到过有关说明,杨晓峰老师说Integer类设计成不可变跟getInteger()方法有关系,getInteger()方法的源码如下:

publicstaticIntegergetInteger(Stringnm,Integerval){Stringv=null;try{v=System.getProperty(nm);}catch(IllegalArgumentException|NullPointerExceptione){}if(v!=null){try{returnInteger.decode(v);}catch(NumberFormatExceptione){}}returnval;}

getInteger()方法是用来获取系统属性的,我们通过属性来设置服务器的某个服务器的端口,如果Integer可变的话,那么我们就能够轻易的改变这个属性的值,这会使得我们的产品存在安全风险。

上面我们我么简单的聊了一下Integer类的实现,聊到int与Integer,自然就少不了自动装箱和自动拆箱。

1、自动装箱、拆箱

自动装箱和拆箱是从JDK1.5开始引进的功能,它是一种语法糖,Java可以根据上下文,自动的在原始类型和包装类型中进行转换,简单的来说就是Java平台保证了不同的写法通过编译之后会产生相同的字节码,保证了运行时是等价的。自动装箱和拆箱极大地简化了相关编程。

自动装箱:将原始类型转化为包装类型的过程

比如将int类型转换成integer类型,这就是原始类型到包装类型的转变,在编译的时候,编译器就会帮我们做自动转换,这个过程对我们程序员来说是无感知的,例如这段给Integer对象赋值的代码:

Integerx=3000;

这段代码经过编译器之后,会转换成下面这段代码:

Integerx=Integer.valueOf(3000);

这就是自动装箱过程,这个过程你是不知道的,所以它才叫自动装箱,在自动装箱的过程中使用到了valueOf()方法,来看看JDK中这个方法的源码:

publicstaticIntegervalueOf(inti){if(i>=IntegerCache.low&&i<=IntegerCache.high)returnIntegerCache.cache[i+(-IntegerCache.low)];returnnewInteger(i);}

这个方法里,前面先进行了一个缓存判断,如果你不知道的话,先忽略掉它,最后返回了newInteger(i)对象引用,这个方法就是帮你去调用了Integer类的构造器。这就是自动装箱。

自动拆箱:将包装类型转换成原始类型的过程

将Integer类型转换为Int类型,这是一个包装类型转成成原始类型的过程,在这个过程中就会涉及到自动拆箱。来看看这段代码(这是一段很操蛋的代码,实际中应该没人这样写):

Integermm=1000;intmmm=mm;

在编译的时候,这段代码会被编译器编译成下面这段代码:

Integermm=Integer.valueOf(1000);intmmm=mm.intValue();

主要看intmmm=mm.intValue();这行代码,这行代码跟我们写的不一样了,使用到了一个intValue()方法,来看看Integer类中intValue()方法的源码:

/***Returnsthevalueofthis{@codeInteger}asan*{@codeint}.*/publicintintValue(){returnvalue;}

这个方法的作用就是把Integer对象中用来存储值的value变量返回了,这就是自动拆箱,好了,关于自动装箱和自动拆箱我们都了解了,还记得自动装箱过程中涉及到的缓存吗?接下来我们一起了解一下。

2、Integer缓存策略

在自动装箱的valueOf()方法中,我们看到了有一个缓存判断的操作,是的,Integer类中有缓存池,会将使用频繁的值缓存起来,以便提高系统的使用性能,在自动装箱的过程中,会先判断该值是否存在缓存池中,如果存在直接从缓存池中取出引用返回,如果不存在则调用构造函数构造对象。缓存是自动装箱操作独享的,直接通过构造函数构造出来的Integer对象即使值在缓存范围内,也不会使用到缓存池。在Integer类中,使用了一个内部类来实现缓存,这个内部类叫做IntegerCache,IntegerCache类的源代码如下:

/***Cachetosupporttheobjectidentitysemanticsofautoboxingforvaluesbetween*-128and127(inclusive)asrequiredbyJLS.**Thecacheisinitializedonfirstusage.Thesizeofthecache*maybecontrolledbythe{@code-XX:AutoBoxCacheMax=<size>}option.*DuringVMinitialization,java.lang.Integer.IntegerCache.highproperty*maybesetandsavedintheprivatesystempropertiesinthe*sun.misc.VMclass.*/privatestaticclassIntegerCache{staticfinalintlow=-128;staticfinalinthigh;staticfinalIntegercache[];static{//highvaluemaybeconfiguredbypropertyinth=127;StringintegerCacheHighPropValue=sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if(integerCacheHighPropValue!=null){try{inti=parseInt(integerCacheHighPropValue);i=Math.max(i,127);//MaximumarraysizeisInteger.MAX_VALUEh=Math.min(i,Integer.MAX_VALUE-(-low)-1);}catch(NumberFormatExceptionnfe){//Ifthepropertycannotbeparsedintoanint,ignoreit.}}high=h;cache=newInteger[(high-low)+1];intj=low;for(intk=0;k<cache.length;k++)cache[k]=newInteger(j++);//range[-128,127]mustbeinterned(JLS75.1.7)assertIntegerCache.high>=127;}privateIntegerCache(){}}

从源码和Java注释中我们可以看出IntegerCache的缓存默认值范围-128~127。但是我们也可以在启动时通过JVM命令来设置缓存范围的最大值,只需要在启动时添加-XX:AutoBoxCacheMax=参数就可以了,但是记得这个size可不要乱设置,需要全方位考虑,比如你设置成10万,那么这10万个数都会在启动刚启动时就添加到内存中,想想这会占用你多少内存?这样做就得不偿失了,Java公司设置成-128~127是有道理的,发现大部分人使用的值都在-128~127之间,这些值占用的内存比较少,性能上比通过构造函数构造对象要好不少。如何你使用的Integer的值在缓存范围的话,就用Integeri=value的形式构建对象,如果你的值不在缓存范围内,则使用Integeri=newInteger(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源代码:

publicstaticintparseInt(Strings,intradix)throwsNumberFormatException{/**WARNING:ThismethodmaybeinvokedearlyduringVMinitialization*beforeIntegerCacheisinitialized.Caremustbetakentonotuse*thevalueOfmethod.*/if(s==null){thrownewNumberFormatException("null");}if(radix<Character.MIN_RADIX){thrownewNumberFormatException("radix"+radix+"lessthanCharacter.MIN_RADIX");}if(radix>Character.MAX_RADIX){thrownewNumberFormatException("radix"+radix+"greaterthanCharacter.MAX_RADIX");}intresult=0;booleannegative=false;inti=0,len=s.length();intlimit=-Integer.MAX_VALUE;intmultmin;intdigit;if(len>0){charfirstChar=s.charAt(0);if(firstChar<'0'){//Possibleleading"+"or"-"if(firstChar=='-'){negative=true;limit=Integer.MIN_VALUE;}elseif(firstChar!='+')throwNumberFormatException.forInputString(s);if(len==1)//Cannothavelone"+"or"-"throwNumberFormatException.forInputString(s);i++;}multmin=limit/radix;while(i<len){//AccumulatingnegativelyavoidssurprisesnearMAX_VALUEdigit=Character.digit(s.charAt(i++),radix);if(digit<0){throwNumberFormatException.forInputString(s);}if(result<multmin){throwNumberFormatException.forInputString(s);}result*=radix;if(result<limit+digit){throwNumberFormatException.forInputString(s);}result-=digit;}}else{throwNumberFormatException.forInputString(s);}returnnegative?result:-result;}

在调用parseInt方法时,我们可以传入一个radix变量,用来告诉它使用什么进制来进行转换,默认使用的是十进制。

文章不足之处,望大家多多指点,共同学习,共同进步

最后

打个小广告,欢迎扫码关注微信公众号:「平头哥的技术博文」,一起进步吧。


您需要登录后才可以回帖 登录 | 立即注册

触屏版| 电脑版

技术支持 历史网 V2.0 © 2016-2017