今天学习了下对象的克隆,其中克隆有以下三条约定
- 对于所有对象来说,x.clone() !=x 应当返回 true,因为克隆对象与原对象不是同一个对象;
- 对于所有对象来说,x.clone().getClass() == x.getClass() 应当返回 true,因为克隆对象与原对象的类型是一样的;
- 对于所有对象来说,x.clone().equals(x) 应当返回 true,因为使用 equals 比较时,它们的值都是相同的。
而对于第3条中的描述:“x.clone().equals(x) 应当返回 true”表示了疑问,因为我们知道:
1. ==:对于基础类型数据来说,比较的是值,对于引用数据来说,比较
的是地址那一串字符串是否相等。
2. equals:看源码得知,Object的equals,也只是用==比较了两个对
象,所以根本就没啥意义,而String重写了equals方法,对引用所指
向的值进行比较
Object:
public boolean equals(Object obj) {
//相等于还是只比较了引用字符串是否相等
return (this == obj);
}
String:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
正是由于objec的equals方法比较的引用,所以x.clone().equals(x) 返回的应该是false,怎么会返回true呢。
随后我写方法进行试验,分别使用了@Data和不使用@Data两种方式进行了测试(也是无意间发现的,不要问为啥专门测了这两种)
@Data
public class Clon1 implements Cloneable {
private String name;
private String age;
public Clon1(String name, String age) {
this.name = name;
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) throws Exception {
Clon1 clon1 = new Clon1("clon1","20");
Clon1 clon2 = (Clon1) clon1.clone();
System.out.println(clon1==clon2);//false
System.out.println(clon1.equals(clon2));//true
}
}
/**************不使用@Data↓↓↓↓********************************/
public class Clon1 implements Cloneable {
private String name;
private String age;
public Clon1(String name, String age) {
this.name = name;
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) throws Exception {
Clon1 clon1 = new Clon1("clon1","20");
Clon1 clon2 = (Clon1) clon1.clone();
System.out.println(clon1==clon2);//false
System.out.println(clon1.equals(clon2));//false
}
}
最后发现,使用了@Data注解的类,经过编译反编译,发现它不仅提供了set、get方法,还重写了equals方法,而equals方法,则对对象中的属性值进行比较,全部相等则返回为true
使用@Data注解时重写的equals方法
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Clon1)) return false;
Clon1 other = (Clon1)o;
if (!other.canEqual(this)) return false;
Object this$name = getName();
Object other$name = other.getName();
if (this$name == null ? other$name != null : !this$name.equals(other$name))
return false;
Object this$age = getAge();
Object other$age = other.getAge();
return this$age == null ? other$age == null : this$age.equals(other$age);
}
protected boolean canEqual(Object other) { return other instanceof Clon1; }
至此,使用@Data注解与不使用注解时,为啥equals结果会是不同的结果,也随之解开了:正是因为 @Data注解重写了equls方法。