本篇blog主要介绍装箱拆箱问题,怎么实现的,有什么问题?首先 通过一道例题分析看几个基本函数表示什么:
设有下面两个赋值语句: a = Integer.parseInt("1024"); b = Integer.valueOf("1024").intValue(); 下述说法正确的是() A, a是整数类型变量,b是整数类对象。 B, a是整数类对象,b是整数类型变量。 C, a和b都是整数类对象并且它们的值相等。 D, a和b都是整数类型变量并且它们的值相等。
涉及的函数表示意义如下:
- intValue()是把Integer对象类型变成int的基础数据类型;
- parseInt()是把String 变成int的基础数据类型;
- ValueOf()是把String 转化成Integer对象类型;(现在JDK版本支持自动装箱拆箱了。)
本题:parseInt得到的是基础数据类型int,valueof得到的是装箱数据类型Integer,然后再通过valueInt转换成int,所以选择D
基础类型和包装类型
每种基础类型都会对应一种包装类型,它们的对应关系如下:
类型转换
那么基础类型和包装类型是如何进行类型转换的呢?
下面赋值语句中正确的是() A double d=5.3e12; //科学计数表示方法,需要注意的是表示范围是否越界 B float f=11.1; //double-->float 精度丢失,需要强转 C int i=0.0; //double-->int 精度丢失,需要强转 D Double oD=3
在不加任何后缀情况下,整型默认为 int 浮点默认为 double,对于D选项,3是int类型,Double是包装器类型无法自动转型,所以应该表示为
double d= 3; 自动转型,int-->double Double d = (double) 3; 强转+自动装箱
比较操作
通过一道例题来分析以下==
和equals
的相关比较操作
Integer i = 42; //装箱 Long l = 42l; Double d = 42.0;
下面为true的是
A (i == l) B (i == d) C (l == d) D i.equals(d) E d.equals(l) F i.equals(l) G l.equals(42L)
依据三条原则来进行分析判断
- 1,对于值类型来说比较大小就可以了,对于引用类型来说来说==比较的是地址,equals比较的是类型+值(重写过,否则引用地址不同也不能相等)
- 2,包装类的“==”运算在遇到基本类型的情况下会自动拆箱
- 3,包装类的equals()方法不处理数据转型
分析上题,ABC选项,都是包装类,引用类型,比较的是地址,地址不同,编译错误,DEF选项,因为equals方法不处理数据转型,所以还是比较类型,所以是错的,G是先对42L装箱,然后比较类型是否相同,如果相同,再比较值大小是否相同,显然都相同
==比较
基本型和基本型封装型进行“==”运算符的比较。
自动拆箱
基本型封装型将会自动拆箱变为基本型后再进行比较,因此Integer(0)会自动拆箱为int类型再进行比较,显然返回true;
int a = 220; Integer b = 220; System.out.println(a==b);//true
两个基本型的==操作就是比值(不管是不是同类型的基本型),但两个封装型的会先判断类型,类型不同报错,并且即使是同一类型也为false,因为引用指向的地址不同
Integer特殊的值范围
两个Integer类型(Integer.valueOf)进行“==”比较, 如果其值在**-128至127** ,那么返回true,否则返回false, 这跟Integer.valueOf()的缓冲对象有关。
Integer c=3; Integer h=3; Integer e=321; Integer f=321; System.out.println(c==h);//true System.out.println(e==f);//false
这个方法就是返回一个 Integer 对象,只是在返回之前,看作了一个判断,判断当前 i 的值是否在 [-128,127] 区别,且 IntegerCache 中是否存在此对象,如果存在,则直接返回引用,否则,创建一个新的对象。 创建新对象后当然就是不同的引用了。源代码如下:
public static Integer valueOf(inti) { assertIntegerCache.high>=127; if(i >= IntegerCache.low&& i <= IntegerCache.high) return IntegerCache.cache[i+ (-IntegerCache.low)]; return new Integer(i); }
Integer非特殊情况
但无论如何,Integer与new Integer不会相等。不会经历拆箱过程
package test; /** * @author 田茂林 * @data 2017年9月6日 下午9:46:42 */ public class TestFinally { public static void main(String[] args) { Integer i= 57; Integer l = new Integer(57); if(i==l){ System.out.println("true"); }else{ System.out.println("false"); //输出为false } } }
equals比较
两个基本型的封装型进行equals()比较,首先equals()会比较类型,如果类型相同,则继续比较值,如果值也相同,返回true
Integer a=1; Integer b=2; Integer c=3; System.out.println(c.equals(a+b));//true
自动装箱
基本型封装类型调用equals(),但是参数是基本类型,这时候,先会进行自动装箱,基本型转换为其封装类型,再进行比较
int i=1; int j = 2; Integer c=3; System.out.println(c.equals(i+j));//true I==L
基本型不能调用equals()方法,否则编译会报错
综合举例
看下边这样一道题进行分析。
package test; /** * @author 田茂林 * @data 2017年9月6日 下午9:46:42 */ public class TestFinally { public static void add(Byte b) { b = b++; } public static void main(String[] args) { Byte a = 127; Byte b = 127; add(++a); //自动拆箱 System.out.print(a + " "); add(b); System.out.print(b + ""); } }
运行结果
-128 127
public void add(Byte b){ b=b++; }
这里涉及java的自动装箱/自动拆箱(AutoBoxing/UnBoxing) Byte的首字母为大写,是类,看似是引用传递,但是在add函数内实现++操作,会自动拆箱成byte值传递类型,所以add函数还是不能实现自增功能。也就是说add函数只是个摆设,没有任何作用
- add(++a);,Byte类型值大小为-128~127之间。 add(++a);这里++a会越界,a的值变为-128
- add(b),没有变化,还是127
以上就是装箱拆箱的全部内容理解,可以看的出Java对equals有了重写,对于操作符==没有重写
- ==:它的作⽤是判断两个对象的地址是不是相等。即,判断两个对象是不是同⼀个对象(基本数据类型⽐较的是值,引⽤数据类型⽐较的是内存地址
- equals(): 它的作⽤也是判断两个对象是否相等。但它⼀般有两种使⽤情况:
- 类没有覆盖 equals() ⽅法。则通过 equals() ⽐较该类的两个对象时,等价于通过“==”⽐较这两个对象。
- 类覆盖了 equals() ⽅法。⼀般,我们都覆盖 equals() ⽅法来⽐较两个对象的内容是否相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)
结合装箱拆箱以及比较的实现来理解更加深刻