Java中equals与==异同
为了更好的理解,先来看看java的数据类型
java的数据类型分为两大类:基本数据类型 与 引用数据类型。
基本数据类型有8种:
数值型:byte int short long
字符型:char
布尔型:bool
引用数据类型有3种:
类:Class
接口:Interface
数组:Array
再有,基本数据类型也有与自己相对应的封装类,即引用类型:
数值 :Byte、Short、Integer、Long、Float、Double
字符:Character
布尔:Boolean
在java中基本数据类型都被统一放在一块区域(内存的栈中),其中有一部分区域称之为“常量池”。
在常量池中,基本数据类型可以被共享,也就是说我们定义一个int a = 5;然后又定义了一个int b = 5;这时a与b在内存中指向的是同一个5。
而对于引用数据类型来说,一个引用数据类型的变量保存的就是这个引用数据类型的引用,即地址。如:String s = “abc” s保存的就是一个地址。
好了 现在进入正题: equals与==的区别
简单来说:equals比较的是值,==比较的是地址。带着这样的前提会帮你理解下面的废话…
看下面一段代码:
1 String s1 = new String("abc"); 2 String s2 = "abc"; 3 if(s1 == s2){ 4 System.out.println("s1 == s2"); 5 } 6 if(s1.equals(s2)){ 7 System.out.println("s1 equals s2"); 8 }
输出结果是:“s1 equals s2”。这是为什么?,s1与s2明明都是"abc"呀,难道“s1 != s2”吗。
事情是这个样子的:
虽然两个语句都是返回一个String对象的引用,但是jvm对两者的处理方式是不一样的。对于第一种,jvm会马上在heap中创建一个String对象,然后将该对象的引用返回给用户。对于第二种,jvm首先会在内部维护的strings pool(可以称之为字符串池)中通过String的 equels 方法查找是strings pool中是否存放有该String对象,如果有,则返回已有的String对象给用户,而不会在heap中重新创建一个新的String对象;如果strings pool中没有该String对象,jvm则在heap中创建新的String对象,将其引用返回给用户,同时将该引用添加至strings pool中。注意:使用第一种方法创建对象时,jvm是不会主动把该对象放到strings pool里面的,除非程序调用 String的intern方法:str.intern();
intern是这样工作的:首先查看strings pool中有无“abc”对象的引用,有则返回那个”abc”的引用。没有,则在堆中新建一个对象,然后将新对象的引用加入到strings pool中。
是不是很眼熟,没错,这不就是刚刚第一个代码例子中 String s2 = “abc”;的时候jvm所做的事情么。所以说,用String来声明字符串,结果都会至少有一个String对象存在的。
与之对应的基本数据类型的封装类中有一些也具有常量池技术:
这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。并且Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127时才可使用对象池,也即对象不负责创建和管理大于127的这些类的对象。
明白原理之后回头再看看:
来看看==:
通常可以这样定义一个变量:int a = 1; int b = 1;
a与b都是基本数据类型,会被放在常量池中,而且此时因为java的常量池共享,此时常量区中只有一个1,所以if(a == b)返回位true。因为a和b的无论是值还是地址都是相等的。(这里不能用equals比较,因为equals是Object类的方法。)
现在看看equals:
上面说了,equals是继承自Object类的一个方法,所以所有引用类型都可以使用equals方法。
然后记住:声明一个类的实例,要用new关键字 ,所以String str1 = “hello world”;String str2 = “hello world”; 这两个肯定是相等的,因为没有用到new 所以java虚拟机会与处理基本类型一样,去常量池查看是否已存在一个”hello world”,如果有则不再新增,str1,str2都指向这个”hello world”。
我们可以用new关键字这样实例化一个String对象:String s1 = new String(“abc”) ; String s2 = new String(“abc”)。
s1 与 s2 是引用数据类型 所以if(s1.equals(s2))返回的是true,而if(s1 == s2)则返回false。这是因为s1与s2都是有用new关键字声明出的新对象,各自有各自的地盘,互不相干。虽然值是一样的,但是存储的位置却不一样,就好像一个楼里有两个同名的人,但是两人住不是一个房间,你对其一操作,不会影响另一个。所以==所比较出的是地址是否相同。当然是false了。
这也证实了开始说的:equals比较的是值,==比较的是地址。
另外:Object类中的equals方法,其代码就是==操作。在没有复写Object的equals方法时调用的话,其实就是使用==。固有的引用数据类型已经复写了equals方法,如String类。
Object类中的equals方法:
1 public boolean equals(Object obj) { 2 return (this == obj); 3 }