Java基础篇:equals()方法与==的区别

1、超类Object的equals()底层原理:

在Object超类中已经提供了equals()方法,源码如下:

public boolean equals(Object obj) {   return (this == obj);     }

所有的对象都拥有标识(内存地址)和状态(数据),同时“==”比较的是两个对象的内存地址,在Object的equals()底层调用的是==号,所以说Object的equals()是比较两个对象的内存地址是否相等,如果为true,则表示的引用的是同一个对象。

2、equals()与 == 的区别:

(1)== 号在比较基本数据类型时比较的是数据的值,而比较引用类型时比较的是两个对象的地址值;

(2)equals()不能用于基本的数据类型,对于基本的数据类型要用其包装类。

(3)默认情况下,从Object继承而来的 equals 方法与 “==” 是完全等价的,比较的都是对象的内存地址,因为底层调用的是 “==” 号,但我们可以重写equals方法,使其按照我们的需求方式进行比较,如String类重写equals()方法,使其比较的是字符的内容,而不再是内存地址。

3、equals()的重写规则:

  • 自反性。对于任何非null的引用值x,x.equals(x)应返回true。

  • 对称性。对于任何非null的引用值x与y,当且仅当:y.equals(x)返回true时,x.equals(y)才返回true。

  • 传递性。对于任何非null的引用值x、y与z,如果y.equals(x)返回true,y.equals(z)返回true,那么x.equals(z)也应返回true。

  • 一致性。对于任何非null的引用值x与y,假设对象上equals比较中的信息没有被修改,则多次调用x.equals(y)始终返回true或者始终返回false。

  • 对于任何非空引用值x,x.equal(null)应返回false。

4、有关equals()与 == 号的小例子:

public class Test {
	public static void main(String[] args) {	
		String str1 = new String("abc");
		String str2 = new String("abc");
		System.out.println(str1 == str2);//false
		System.out.println(str1.equals(str2));//true
		
		String str3 = "123";
		String str4 = "123";
		System.out.println(str3 == str4);//true
		System.out.println(str3.equals(str4));//true	
	}
}

根据上面的demo输出结果可以看到,前面的输出结果是false、true,后面的输出结果是true、true。为什么两次==的输出结果不一样呢?这其实涉及到了内存中的常量池,常量池属于方法区的一部分,当运行到创建str3对象时,如果常量池中没有“123”,则在常量池中创建一个"123"对象,运行到str4对象时,由于“123”已经存在常量池,就直接使用,所以str3和str4对象其实是同一个对象,他们的地址引用相同。

而对于str1和str2,它们其实创建了两次对象,一次在常量池创建了对象“abc”,所以str1和str2的地址值是不相等的。

5、重写equals()中 getClass 与 instaceof 的区别:

在重写equals() 方法时,一般都是推荐使用 getClass 来进行类型判断,不是使用 instanceof(除非所有的子类有统一的语义才使用instanceof)。我们都知道 instanceof 的作用是判断其左边对象是否为其右边类的实例,返回 boolean 类型的数据,可以用来判断继承中的子类的实例是否为父类的实现。

下来我们来看一个例子:父类Person

public class Person {
        protected String name;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Person(String name){
            this.name = name;
        }
        public boolean equals(Object object){
            if(object instanceof Person){
                Person p = (Person) object;
                if(p.getName() == null || name == null){
                    return false;
                }
                else{
                    return name.equalsIgnoreCase(p.getName ());
                }
            }
            return false;
       }
    }

子类 Employee:

public class Employee extends Person{
        private int id;
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public Employee(String name,int id){
            super(name);
            this.id = id;
        }
        /**
         * 重写equals()方法
         */
        public boolean equals(Object object){
            if(object instanceof Employee){
                Employee e = (Employee) object;
                return super.equals(object) && e.getId() == id;
            }
            return false;
        }
    }

上面父类 Person 和子类 Employee 都重写了 equals(),不过 Employee 比父类多了一个id属性,而且这里我们并没有统一语义。测试代码如下:

public class Test {
        public static void main(String[] args) {
            Employee e1 = new Employee("employee", 23);
            Employee e2 = new Employee("employee", 24);
            Person p1 = new Person("employee");
            System.out.println(p1.equals(e1));//true
            System.out.println(p1.equals(e2));//true
            System.out.println(e1.equals(e2));//false
        }
    }

上面代码我们定义了两个员工和一个普通人,虽然他们同名,但是他们肯定不是同一人,所以按理来说结果应该全部是 false,但是事与愿违,结果是:true、true、false。对于那 e1!=e2 我们非常容易理解,因为他们不仅需要比较 name,还需要比较 ID。但是 p1 即等于 e1 也等于 e2,这是非常奇怪的,因为 e1、e2 明明是两个不同的类,但为什么会出现这个情况?首先 p1.equals(e1),是调用 p1 的 equals 方法,该方法使用 instanceof 关键字来检查 e1 是否为 Person 类,这里我们再看看 instanceof:判断其左边对象是否为其右边类的实例,也可以用来判断继承中的子类的实例是否为父类的实现。他们两者存在继承关系,肯定会返回 true 了,而两者 name 又相同,所以结果肯定是 true。所以出现上面的情况就是使用了关键字 instanceof,这是非常容易导致我们“钻牛角尖”。故在覆写 equals 时推荐使用 getClass 进行类型判断。而不是使用 instanceof(除非子类拥有统一的语义)。 

  • 31
    点赞
  • 132
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张维鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值