转:Java踩坑笔记:基本类型与包装类之间的自动转换

原文出处:https://www.cnblogs.com/shing0315/p/7138515.html

示例如下:

Integer x = 400;
Integer y = x;
x++;
System.out.println(x == y);//false

这里可以“解yan释shi”为x和y都是基本类型,具有值语义(雾),x自增后y不变。

Integer x = 400;
Integer y = x;
System.out.println(x == y);//true

这个例子没毛病,x和y“貌似”都是基本类型。

Integer x = 400;
Integer y = 400;
System.out.println(x == y);//false

开始有点懵逼了,x和y不相等应该是因为触发了自动装箱(基本类型自动转换到包装类)以及Integer的缓存机制(默认-128至127)。

Integer x = 2;
Integer y = 2;
System.out.println(x == y);//true

这个例子也没毛病,因为Integer的缓存机制,数字2的包装类实例被事先被缓存了。

那么问题来了,为什么x和y有时候是值语义有时候是引用语义呢?再做一个实验:

Integer x = 400;
Integer y = 400;
System.out.println(x.equals(y));//true

得到了想要的结果,这时候想起来Integer之间的比较和String之间的比较是相似的。

或者说,这里的核心原理是“==”运算符比较的是两个实例的指针(引用),相等即表示内存地址相同。

还有一点:

int x = 400;
int y = 400;
System.out.println(x == y);//true

这里就没有被自动装箱。

从课本上引用一段话:“如果一个基本类型值出现在需要对象的环境中,编译器会将基本类型值进行自动装箱;如果一个对象出现在需要基本类型值的环境中,编译器将对象进行自动开箱。”

由此可见,自动开装箱与否,是由编译器决定的,这是一个从jdk1.5开始引入的语法糖。

对了,第一个例子和第二个例子的原理就需要重新解释了:

Integer x = 400;//触发自动装箱,等同于Integer x = new Integer(400);
Integer y = x;//没有触发自动转换
System.out.println(x == y);//y的引用和x相同,true了
x++;//触发自动开箱和自动装箱,等同于x = x + 1;(这时候x的引用已经更新了!我之前也没注意到。。)
System.out.println(x == y);//理所当然地false了

更进一步的思考,自动装/开箱的条件,即所谓的需要的环境是怎样的呢?我手头暂时没有更权威的资料,我猜测,赋值的时候根据声明类型来决定,运算的时候根据是否有必要转换来决定。

那么问题都被解决了,由于声明变量的时候声明类型是包装类,所以编译器帮我们把int类型自动装箱成包装类类型;“==”运算符支持对象与对象之间的运算,于是“==”运算符就跑去比较对象了;“=”运算符支持对象引用的赋值,于是“=”运算符就跑去赋引用值了。

得出来的实践经验的话,就是以后要尽量小心Integer,不能随便用来声明整型,毕竟碰上“==”运算符,再加上Integer的缓存机制。这三种东西混在一起,简直要爆炸。。XD

最无脑方便万无一失的方法,统统用equals比较是否相等,哈哈。

彩蛋:

Integer x = 400;
Integer y = 401;
System.out.println(x < y);//true
Integer x = 400;
Integer y = 401;
System.out.println(x > y);//false


猜你喜欢

转载自blog.csdn.net/alyone_23/article/details/80509045