Java学习笔记:(25)基本类型优先于装箱基本类型

java的类型分两部分,基本类型和引用类型。并且,每个基本类型都对应了一个引用的类型,称为装箱基本类型。

如Integer 对应int,Double对应的double.

两者的主要区别有三:

  1. 基本类型只有值,而装箱类型则有与他们的值不同的同一性,也就是两个装箱类型可以具有相同的值,有不同的同一性(不同的引用)
  2. 基本类型只有功能完备的值,而每个装箱类型除了它对应基本类型的所有功能值外,还有个非功能的值--null
  3. 基本类型通常比装箱类型更节省时间和空间。

首先看装箱类型的同一性,自己写的一个比较函数代码如下:

Java代码 收藏代码
  1. //比较器
  2. publicintmyCompare(Integerfirst,Integersecond){
  3. returnfirst<second?-1:(first==second?0:1);
  4. }

该函数用来表示Integer值的递增数字顺序。若第一个参数是小于,等于 或者大于它的第二个参数,则该方法返回负数,0或者正数.

但是该函数并不能正常的工作,当你调用 myCompare(new Integer(44), new Integer(44)),时,函数返回1.

但我们期待的是0。

原因是进行first<second比较时,系统自动对两个Integer对象被进行了自动拆箱,提取了基本类型的值,经过比较44<44不成立,则进行first==second的比较,这时系统进行的是同一性的比较,也就是比较两个包装类的引用,很明显不是同一个引用,所以函数返回1.

结论:对包装类用==操作符几乎总是错误的.

修改的方法是 新增加两个局部的值类型变量来替换。

Java代码 收藏代码
  1. publicintmyCompare(Integerfirst,Integersecond){
  2. //使用两个基本类型来转化,避免进行对象的同一性比较
  3. /*intf=first;
  4. ints=second;
  5. returnf<s?-1:(f==s?0:1);*/
  6. returnfirst<second?-1:(first==second?0:1);
  7. }

再看下面的代码:

Java代码 收藏代码
  1. Integeri1=100;//自动装箱
  2. Integeri2=100;
  3. intj=100;
  4. System.out.println(i1==i2);
  5. System.out.println(i1==j);
  6. Integeri3=128;//自动装箱
  7. Integeri4=128;
  8. intk=128;
  9. System.out.println(i3==i4);
  10. System.out.println(i4==k);

以上代码分别输出结果是什么?

输出的结果是 true,ture,false,true

对于i1和i2的结果,我们很清楚明白,但是对于i3==i4的比较,为什么为false?

当将一个int值赋值给它的一个Integer包装类型变量时,Integer类型调用了valueOf方法:

Java代码 收藏代码
  1. publicstaticIntegervalueOf(inti){
  2. finalintoffset=128;
  3. if(i>=-128&&i<=127){//mustcache
  4. returnIntegerCache.cache[i+offset];
  5. }
  6. returnnewInteger(i);

如果这个值在-128和127之间,则将该值进行了缓存处理,在内存中都是指向的一个包装类型对象.

也就是

Integer i1=100;

Integer i2=100;

Integer i3=100;

Integer i4=100;

...

Integer i100=100;

这些所有的Integer对象都是指向同一个对象地址空间的。

但是超过了这个区间,则分别创建的是不同的Integer对象.

查看IntegerCache中引用cache这个变量的部分:

Java代码 收藏代码
  1. privateIntegerCache(){}
  2. staticfinalIntegercache[]=newInteger[-(-128)+127+1];
  3. static{
  4. for(inti=0;i<cache.length;i++)
  5. cache[i]=newInteger(i-128);
  6. }

由于cache[]在IntegerCache类中是静态数组,也就是只需要初始化一次,即static{......}部分,所以,如果Integer对象初始化时是-128~127的范围,就不需要再重新定义申请空间,都是同一个对象---在IntegerCache.cache中,这样可以在一定程度上提高效率。

看另外的个例子:

Java代码 收藏代码
  1. staticIntegeri;
  2. publicvoidunbelieve(){
  3. if(i==42){//这里将抛出空指向异常因为自动装箱和拆箱的缘故,建议修改i的定义为int或者和new
  4. //Integer(42)包装类型来比较
  5. System.out.println("不敢相信");
  6. }

这里不会输出"不敢相信",系统会报告NullPointerException异常。因为i被初始化为null,使用(i==42)时,因为i是Integer 类型,当包装类型和基本类型进行比较时,包装类型则会被自动拆箱,但i是一null,null对象引用被自动拆箱,则会得到一个NullPointerException异常。

修改的方法是将i定义为int或者将其和包装类进行比较,但同样要注意上面提到的-128~127这个区间的问题

另外一个关于性能的问题,看如下代码:

Java代码 收藏代码
  1. publicstaticvoidmain(Stringargs[]){
  2. Longsum=0L;
  3. for(longi=0;i<Integer.MAX_VALUE;i++){
  4. sum=+i;
  5. }
  6. System.out.println(sum);
  7. }

这个程序中的的局部变量 sum 被声明为装箱类型Long,不是基本类型long,虽然编译和运行没有任何错误。但明显的,其在运行中被反反复复的装箱和拆箱,严重影响了性能。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值