在Java学习和面试中经常遇到这个问题,虽然想着简单,但还是决定记录下来,毕竟菜嘛…
1.“==”
==是直接比较的两个对象的堆内存地址,如果相等,则说明这两个引用实际是指向同一个对象地址的。但是我们又常常碰到这样一个问题
运行结果:
从结果可以看出,那既然 == 是比较地址,那么int数据的地址是怎样的呢,String又是怎样的呢?
对于**基本数据类型(byte,short,char,int,float,double,long,boolean)**来说,他们是作为常量在方法区中的常量池里面以HashSet策略存储起来的,对于这样的字符串 “123” 也是相同的道理,在常量池中,一个常量只会对应一个地址,因此不管是再多的 123,“123” 这样的数据都只会存储一个地址,所以他们的引用都是指向的同一块地址,因此基本数据类型和String常量是可以直接通过==来直接比较的。
另外,对于基本数据的包装类型(Byte, Short, Character,Integer,Float, Double,Long, Boolean) 除了Float和Double之外,其他的六种都是实现了常量池的,因此对于这些数据类型而言,一般我们也可以直接通过==来判断是否相等。那么再出一个问题考考大家 ↓
猜猜结果是啥呢?
————————————————————————————————————
结果是 true,false。没想到吧!其实是因为 Integer 在常量池中的存储范围为[-128,127],127在这范围内,因此是直接存储于常量池的,而128不在这范围内,所以会在堆内存中创建一个新的对象来保存这个值,所以m,n分别指向了两个不同的对象地址,故而导致了不相等。
2、equals()方法
很多伙伴都说equals比较的是对象的内容,这样的说法是不准确的。
首先我们来看看在Object类中定义的equals方法[源码] ↓
可以看到其源码,在Object类型的equals方法是直接通过== 来比较的,和 ==是没有任何区别的。
那么为什么又要说equlas和==的区别呢?是因为equals方法是可以由我们自己重写的。
众所周知,我们所有的类都直接或间接地继承自java.lang.Object类,因此我们可以通过重写equals方法来实现我们自己想要的比较方法。来看看eclipse编译器为我们自动生成的equals方法 ↓
(1)手写equals
(2)系统自动生成equals(快捷键:Shift+Alt+S)
可以看出,eclipse编译器还是很智能的,它首先是判断两个对象的地址是否相等,若不相等再进行下面的成员变量判断。
但这个方法体是完全可以由我们自己实现的,即便是我们直接 return true 都是可以的,只要能满足我们的业务需求,怎样写都是无所谓的。因此,equals比较的并不一定是对象的内容,它还可以由其他的信息来指导比较。
3、总结
- “==”的作用是判断两个对象的地址是不是相等。即判断两个对象是不是同一个对象。(基本数据类型 == 比较的是值,引用数据类型 == 表示的是内存地址)
- equals():它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
(注意:equals() 方法不能作用于基本类型的变量,但基本类型对应的包装类是可以的)
(1)类没有覆盖(重写)equals()方法,则通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象。(具体见上面的源码)【即:比较的是引用类型的变量所指向的对象的内存地址】
(2)类覆盖了equals()方法,一般我们都是重写此方法来比较两个对象的内容是否相等,若它们的内容相等,则返回true(即:认为这两个对象相等)。【即:比较的是所指向的对象的内容(如:String、Date类等)】
因此,“==”与equals()方法知识点并不多,但是确实很容易混淆,我个人建议结合代码去理解知识点,把二者区别分清楚,还有要灵活重写equals()方法。