首先抛出一个问题:
public static void main(String[] args) {
System.out.println("字符串直接==:"+("qq"=="qq"));
System.out.println("字符串equals判别:"+"qq".equals("qq"));
String s1=new String("qq");
String s2=new String("qq");
System.out.println("字符串直接==:"+(s1==s2));
System.out.println("字符串equals判别:"+s1.equals(s2));
}
输出结果:
字符串直接==:true
字符串equals判别:true
字符串直接==:false
字符串equals判别:true
问题简述:String类的基本数据类型用==和equals()都可以直接判断内容,而String类的对象用equals可以,==却失灵了。
原因:==默认只能判断两个东西,对于基本数据类型直接判断值,对于引用数据类型判断其地址编码。两个String对象的地址不同(两个“qq”在内存中各有一块位置),==自然失灵。
至于两个String类基本数据类型怎么判断相等,涉及常量池的问题,简单来说就是当某个字符串第一次出现,常量池中存储其内容和地址,再次声明同一个字符串时直接调用常量池中的这个。
这样看起来equals似乎很灵活,好像既是不是一个对象也可以直接判断内容。那么我们看看其他类型如何:
class User{ //定义一个User类
String name;
int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
User u1=new User("qq",11); //创建两个User对象
User u2=new User("qq",11);
System.out.println(u1.equals(u2)); //equals判别对象是否相等
}
}
输出结果:
false
原因:equals方法的源代码如下:
public boolean equals(Object obj) {
return (this == obj);
}
也就是说,对于一般的数据类型(我们不知道有没有Object的子类重写过equals方法,但自己写的类一定没有重写过),调用equals和用==没有区别。
那么String为什么特殊呢?我们看String类的源代码:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
return (anObject instanceof String aString)
&& (!COMPACT_STRINGS || this.coder == aString.coder)
&& StringLatin1.equals(value, aString.value);
我们可以看到String对象的内容(值/value)在底层是一个byte类型的数组,而String源代码重写了equals方法,在==判别之后又进行了关于value的判别。也就是说对String的equals方法能够考察到具体值。
那我们再看一个:
String s1=new String("qq");
String s2=new String("qq");
Object o1=s1; //String对象向上转型到Object
Object o2=s2;
boolean eo=o1.equals(o2);
System.out.println("o1.equals(o2) is "+eo);
Object o11=new Object(); //创建Object对象,其内容是String
o11=1;
Object o22=new Object();
o22=1;
System.out.println("o11==o22 is "+(o11==o22));
System.out.println("o11.equals(o22) is "+o11.equals(o22));
测试结果:
o1.equals(o2) is true
o11==o22 is true
o11.equals(o22) is true
问题简述:Object类调用equals方法为什么还能具体判断内容是否相等?
原因:只要子类重写了,那么无论是父类对象还是子类对象再次调用,都会优先调用子类对象。
这样看来equals方法有点鸡肋,程序员们对于这个关键字很执着,于是对于不同类要重写equals。
代码如下:
class User{
String name;
int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public boolean equals(Object ano) {
if(this==ano) {
return true;
}
if (!(ano instanceof User)) {
return false;
}
User anouser = (User) ano;
//System.out.println("参数向下转型————"+anouser);
return name.equals(anouser.name)&&age==anouser.age;
}
这个代码是针对User类重写了关于User的equals方法,基本思想是逐个判断属性是否相等。
具体而言:代码13行表示:如果==成立,表示两个对象地址编码相同,那么内容一定是相同的。
代码16行表示:如果作为方法参数的对象ano不是User类,那么一定和调用此方法的this对象不同。
代码19行目的是将ano向下转型为User,毕竟只要User类对象才能和User对象相等。(为什么ano只能按照Object类型接收呢?因为重写方法要求方法名,参数均不变,当我们将User类作为参数时它会自动向上转型到Object类这才需要向下再转型。当然如果不重写equals方法,而是针对某个对象单独写判别方式肯定可以)。
代码21行表示:对于name属性和age属性分别判断是否相等。
新人入门,格外大佬多多指教。