【Java基础】“equals” 和 “==”的理解
简述:
==: 用于基本类型和引用类型:当用于基本类型时候,是比较值是否相同;当用于引用类型的时候,是比较对象(内存地址)是否相同;
equals: java.lang包中的Object类有public boolean equals(Object obj) { return (this == obj) }方法,它比较两个对象是否相等;
故对于引用类型在一定程度上,"==" 和 "equals"的功能是一致的,都是比较对象(内存地址)是否相同;
1、JDK常用类的“==”和“equals()”的区别:
JDK中常用类String、基础类型的封装类型都重写了equals()方法,故才有下例的中的结果:
//String重写了Object的equals()方法,比较相同index的字符是否一致(基础类型char的比较"==") //同时也发现基础类型的封装类型,同样也重写了equals()方法,故平时使用时equals()给我们的印象是比较本身的值是否相同; //char[Character], byte[Byte], short[Short], int[Integer], long[Long], float[Float], double[Double], boolean[Boolean] String a = new String("s"); String b = new String("s"); System.out.println(a.equals(b));//print true System.out.println(a == b);//print false
故在引用类型的比较上,个人感觉equals()方法是对“==”的补充,完成“==”做不到的功能(比较对象的内容是否相同)!
2、String类中“==”的细节:
对于引用类型,“==”比较对象(内存地址)是否相同,但是下例中的结果却并不完全遵循上述的描述:
String a = new String("s"); String c = "s"; String d = "s"; System.out.println(c == d); //print true System.out.println(c == a); //print false
其原因:在JVM内,存在字符串池,其中保存着很多 String对象,并且可以被共享使用。
其过程:如果要创建下一个字符串对象,JVM首先会到字符串池中寻找,是否存在对应的字符串对象,如果存在,则返回一个己存在对象的对象的引用给要创建的对象引用.
如果不存在,才会创建一个新的对象,并返回一个新对象的对象引用给要创建的对象引用。故例子中 c == d返回值是true。
而对于 String a = new String("s"),共有“s”, a两个String对象,且a是不存放到字符串共享池中的,故例子中c == a返回值是false
上述的描述同样适用于Integer等基础类型的封装类;
3、普通类的“equals()”重写:
受到String类的启发,我们也可以来重写自定义类的equals()方法,如下例:
public class Equals { private String name = ""; private int age = 0; public Equals(String name, int age) { this.name = name; this.age = age; } @Override public boolean equals(Object obj) { if(this == obj){ return true; } if(obj instanceof Equals){ Equals equ = (Equals) obj; return this.name.equals(equ.name) && this.age == equ.age; } return false; } @Override public int hashCode() { return 31 * this.name.hashCode() + ((Integer)this.age).hashCode(); } public static void main(String[] args) { Equals eq1 = new Equals("s", 3); Equals eq2 = new Equals("s", 3); System.out.println(eq1.equals(eq2)); System.out.println(eq1 == eq2); } }
重写equals必须注意:
1. 自反性:对于任意的引用值x,x.equals(x)一定为true
2. 对称性:对于任意的引用值x 和 y,当x.equals(y)返回true,y.equals(x)也一定返回true
3. 传递性:对于任意的引用值x、y和 z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也一定返回 true
4. 一致性:对于任意的引用值x 和 y,如果用于equals比较的对象信息没有被修改, 多次调用x.equals(y)要么一致地返回true,要么一致地返回false
5. 非空性:对于任意的非空引用值x,x.equals(null)一定返回false
6. 重写hashCode:最好同时重写hashCode()方法,否则两个等价的对象可能得到不同的hashCode值,导致使用集合框架出现问题;
hashCode介绍:JDK根据对象的地址或者字符串或者数字算出来的int类型的数值,此方法主要是为了提高哈希表(例如 java.util.Hashtable提供的哈希表)的性能;
通过分析Hashtable的get()方法可以看出key键要同时满足hashCode值、key值,才能获得对应的value键;
public Object get(Object key) { HashtableEntry e; HashtableEntry tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (e = tab[index]; e != null; e = e.next) if ((e.hash == hash) && e.key.equals(key)) return e.value; return null; }