【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;
}        

 

posted on 2014-12-31 17:40  有个姑娘叫小芳  阅读(282)  评论(0编辑  收藏  举报