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
个人见解,有错误欢迎提出
本文深入探讨了Java中equals方法与==运算符在比较基本类型与引用类型时的行为差异,解析了String类中的特殊行为,并提供了重写equals方法的最佳实践。
142





