Java中的细节--equals和==

本文深入探讨了Java中equals方法与==运算符在比较基本类型与引用类型时的行为差异,解析了String类中的特殊行为,并提供了重写equals方法的最佳实践。

Java中的细节–equals和==

在Java的世界里,在基本类型变量中,我们可以使用==来比较两个值是否相等,不强调左右的变量类型

  • ==

比较基本变量

public class EqualsFrist {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int a=65;
		int b=65;
		char c='A';
		//返回true
		System.out.println(a==b);
		//返回true
		System.out.println(a==c);
	}

}

String的一些坑

public class EqualsSecond {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String str1="hello";
		String str2="hello";
		//编译时就可以确定的东西,jvm会把字符串放在常量池中,上述str1和str2分别指向这个字符串,返回true
		System.out.println(str1==str2);
		String str3=new String("hello");
		String str4=new String("hello");
		//看起来str3和str4应该相等啊,但是在使用new String("....")初始化变量时,
		//jvm会先使用常量池来管理hello这个字符串,在调用String类的构造器来创建一个String对象
		//新创建的String对象被保存在堆内存中
		//通俗的说,其实我们创建了两个字符串对象
		//下面比较返回false
		System.out.println(str3==str4);
		//同理
		System.out.println(str1==str3);
		String str5="he"+"llo";
		//看似会不同,但是对于jvm来说,str5同样可以在编译器就确认下来
		//下面比较返回true
		System.out.println(str2==str5);
		String str6="he";
		String str7="llo";
		String str8=str6+str7;
		//受举一反三的影响,我们会轻易的判断下述比较返回true
		//有人会说这不合上面的比较雷同吗,答案也一定大同小异吧
		//如果这么想,你就走弯路了,我们可以说str6和str7是在编译器确定的
		//但是str8不可以这么说
		//原理就是str8看似和str5差不多,但是str8没有引用常量池的字符串
		System.out.println(str1==str8);
	}

}

这里我们不先讲使用equals去比较,在String类中,其实重写了equals方法,我们了解一下equals的源码,这是Object提供的一个方法,因为Object是所有类的超类,所有类都会直接或者间接继承该类,所以所有类都可以去重写equals的方法

  • equals

现在想一个场景,申请QQ号,假如我们规定一个人只能实名注册一个QQ号,当我们信息填写完毕点击实名认证时,是不是应该先看一下这个人有没有实名认证过,在面向对象的思想中,我们不能把对象的一些属性暴露出来,但是我们一定会去比较,先来看下面代码。

public class Person {
	private String name;
	private int age;
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
	
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Person() {
		
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Person p1=new Person("小明",12);
		Person p2=new Person("小明",12);
		//这里就显示出==的缺点了,我们认为应该返回true
		//但是还是返回了false
		System.out.println(p1.equals(p2));//-------①
	}

}

emmmmm,问题在哪?

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

很明显,我们发现其实在底层,我们同样调用了"==",但是对于引用变量,只有在两个变量指向同一块内存地址时,才会返回true,这时,我们就要重写equals了

@Override
	public boolean equals(Object obj) {
		// TODO Auto-generated method stub
		if(this==obj) {
			return true;
		}
		if(obj!=null&&obj.getClass()==Person.class) {
			Person newObj=(Person)obj;
			if(newObj.getAge()==this.getAge()&&newObj.getName().equals(this.getName())) {
				return true;
			}
		}
		return false;
	}

哎。。。还是用了String类的equals,不过道理显而易见了,如果仅仅是基本类型变量,==就好了,但是如果面对引用类型变量,equals需要去自定义,如果写的逻辑有问题的话,有可能会出现 人.equals(狗)返回true ,很可笑,但是在编码的初期还是会出现的,所以给出如下准则
①自反性:x.equals(x)一定返回true
②对称性:x.equals(y) y.equals(z)的返回值相等
③传递性:x.equals(y) y.equals(z) z.equals(x)的返回值相等
④一致性:无论多少次比较,在没有变化的情况下,结果永远不变
⑤空指针和对象比,永远返回false
对于第五条,在编程时一定要注意,在比较变量和常量的情况下(字符串),一定要写成变量.equals(常量)这种形式

变量.equals(常量),如果你的字符串获取失败,则返回空指针异常
常量.equals(变量),如果你的字符串获取失败,则返回false

这个是一种编程习惯,但是提倡,因为会更快找到出错的地方

  • 区别
    在不重写equals方法时,比较对象返回值相等
    对于基本变量:==
    对于引用变量:equals

个人见解,有错误欢迎提出

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值