关于“==”和 equals 的一些疑惑

2016-03-05 19:30:33 +08:00
 mikicomo

“==”和 java.lang 中默认的 equals 实现既然都是对于内存空间中地址的比较,那么为什么可以使用
i == 1这样的写法来判断 i 和 1 是否相等呢?以前倒是从来没有考虑过这个问题,求教下 V 友。

2031 次点击
所在节点    问与答
19 条回复
ovear
2016-03-05 19:46:56 +08:00
i 是什么 Integer ? 基本类型可以
FinalDream
2016-03-05 19:51:54 +08:00
基本类型都在栈里
jsyangwenjie
2016-03-05 20:08:15 +08:00
基本类型
mikicomo
2016-03-05 20:10:17 +08:00
@ovear
@FinalDream
哦哦,所以意思是说,对内存空间地址的比较是相对于“引用”而言的?
ovear
2016-03-05 20:13:14 +08:00
@mikicomo 参见 Cache Pool , Java 在创建这些类型的对象的时候,内部有个表,如果不存在就创建,存在就直接指向。
还是比较内存地址。
mikicomo
2016-03-05 20:16:43 +08:00
@ovear 哦哦,虽然暂时还不是很明白(琢磨着也不一定看得懂 Cach Pool ),但是 mark 了(果然是一个小细节都不能放过啊,以前很理所应当的 逻辑运算符号也有这么大的讲究,)
wmlhust
2016-03-05 21:48:13 +08:00
对于基本类型是直接比较值的吧
对于对象,默认的 equals 是比较引用指向的对象地址
SoloCompany
2016-03-05 22:01:52 +08:00
基本类型和 object 完全是两个世界,==操作符的定义对于基本类型和 object 也是完全无关的
otakustay
2016-03-06 13:13:36 +08:00
@ovear 不是 cache 的关系吧, primitive 的==操作就是内存比较
ovear
2016-03-06 14:10:36 +08:00
@otakustay 是 cache 关系,基本类型都是保证内存中有一个唯一实例。
但是包装类型可以有多个实例。
比如说 new Integer(1);
这个 Integer 本身是新的,但是内部指向的这个 基本类型 1 是唯一确定的。
otakustay
2016-03-06 19:59:30 +08:00
@ovear 你说的是 Integer ,这是一个 object 类型,而楼主表达的是 1 ,这是一个 primitive 类型。==操作符对这两类使用的逻辑是不同的, Integer 是引用比较,因为 cache 的原因一般都会成功,正如你说的;而 primitive 是内存值比较,和 cache 没有啥关系, int 在做==运算的时候也不会进行装箱转为 Interger
同时, Integer 的 cache 也并不可靠,你可以试试
Integer a = new Integer(12);
Integer b = new Integer(12);
System.out.println(a == b);
这并不会给你想要的结果
ovear
2016-03-06 20:51:25 +08:00
@otakustay 关于你说的这个问题,很明显你是没有理解好 Java 的 Cache Pool 以及 Java 的自动拆装箱

Integer a = 12;
Integer b = 12;
Integer c = new Integer(12);
Integer d = 12;

a==b==d
c 和 abc 任意一个都不等

这个才是 cache pool ,建议你看一下相关资料,其他包装类型,包括 String 也有类似的机制

同时注意我上面的话

基本类型都是保证内存中有一个唯一实例。

而 包装类型

保证的是,默认情况下会使用同一个实例,但是你强制使用 new 来创建包装类型, Java 就会忽略 Cache ,直接帮你创建,但是包装类型内部指向的 基本类型 是一样的。


所以不管是基本类型,还是包装类型,比较的都是内存地址。只不过 Java 保证基本类型在内存中有唯一实例,才使得 == 操作符表现出来的行为像是值比较。

(如有错误欢迎指正)
colincat
2016-03-06 21:56:15 +08:00
Intger i=100,如果整型字面量的值在-128 到 127 之间,那么不会 new 新的 Integer 对象,而是直接引用常量池中的 Integer 对象
otakustay
2016-03-07 11:24:46 +08:00
@ovear 我理解楼主说的是下面这个问题:

int i = 1;
int j = 1;
i == j;

这里和 Integer 一点关系也没有, Integer 怎么工作我自然知道。这里的 i 和 j 的内存地址不一样,甚至把 i 通过参数传给另一个函数地址也不同( pass by copy ),但它们可以通过==运算
otakustay
2016-03-07 11:26:55 +08:00
@ovear 另外你试试

Long a = 1234567890;
Long b = 1234567890;
a == b;

不要说基础类型都有 Cache , Cache 是非常有限的
mikicomo
2016-03-07 16:48:05 +08:00
@ovear
@otakustay
没想到一个问题引出两个大大的激烈讨论....
不过我的本意是
int i =1;
i == 1
这样的, otakustay 大大的理解可能有些偏差,不过也正因为如此再次给我打开了新世界的大门...!又接触到了更深一层的东西(虽然简单的还没搞定..)
ovear
2016-03-07 18:49:29 +08:00
@otakustay Long 并不是基础类型,另外多看文档,范围讲的很清楚。
http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.7

@mikicomo
@otakustay

如果是关于
int a = 1;
int b = 1;
这两个基本类型的问题,我之前的理解有问题,之前不知道在哪本书和 zhihu 上看到了,对于基本类型也有个这种东西。但是经过 @大神 之后,证明我我的说法有问题。

基本类型不一定会具备内存地址,可能还会存在于寄存器当中。 http://blog.csdn.net/lm2302293/article/details/6713147
部分类型在 byte code 中是有常量的


0x02
iconst_m1
int 型常量值-1 进栈
0x03
iconst_0
int 型常量值 0 进栈

具体、更专业的说法参考 https://www.zhihu.com/question/26711836/answer/89610502
otakustay
2016-03-07 21:55:42 +08:00
@ovear 纯技术讨论哈
Long 不是基础类型你前面说的 Integer 自然也不是了,不明白这里的矛盾点在哪里
范围当然讲得很清楚,正是因为有这个清楚的范围,所以==依赖 Cache 的存在运用在 Integer 等对象类型上不就是一个 bad practice 么……正确来说,我们任何时候都不应该提倡对 Integer/Long 这样的类型用==操作符才对
tedyhy
2016-03-16 19:34:46 +08:00
@ovear 犀利

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/261356

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX