一、==、equals、hashcode
Java中比较对象通常使用==符和equals方法。
== ⽐较的是对象地址,equals 是Object的一个方法,通常子类通过重写它来比较值。
equals是Object类的方法,实现如下:
public boolean equals(Object obj) {
return (this == obj); 就是调用==
}
Object类中的方法就是==,但是可以通过重写equals方法进行比较。
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;
}
HashCode是Java对象的签名,hashcode可以减少equals比较的次数,提高运算效率。
hashCode是Object类的一个native方法,通过哈希函数给每个对象生成一个哈希值,用来方便Java内部查找对象。
但是哈希是会有冲突的,所以哈希值相同,不代表对象就一定相同。
public native int hashCode();
通常重写equals方法就会重写hashCode方法。
集合 Set 和 Map 加⼊元素会在调⽤他们的 put (Set add ⽅法的背后也是 HashMap 的 put)⽅法时, 会先判断 hash 值是否相等。
二、clone
clone是Cloneable接口的方法,继承该接口可以复制Java对象。
Java是值传递,或者说赋值传递。引用类型通过=并没有被复制,只是被新的句柄(或者说字段)引用了,还是一个对象。一个句柄修改对象后,其他句柄也会受到影响。(在 Java 中,A a1 = a2,我们需要理解的是这实际上复制的是引用,也就是说 a1 和 a2 指向的是同一个对象。因此,当 a1 变化的时候,a2 里面的成员变量也会跟着化。)
重写Cloneable接口的clone方法,可以进行对象的浅拷贝和深拷贝。
浅拷贝
创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是值类型的,那么对该字段执行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象。
因此,原始对象及其副本引用同一个对象。
import java.util.LinkedList;
/**
* @author cgl
* @version 1.0
* @desc
* @date 2021/3/4 9:55
*/
public class ReTry implements Cloneable {
private int id;//基本类型
//引用类型
private LinkedList<Integer> list=new LinkedList<>();
public ReTry() {
this.id = 1001;
this.list.add(10);
}
@Override
protected ReTry clone() throws CloneNotSupportedException {
ReTry c=(ReTry)super.clone(); //调用clone方法
// c.list= (LinkedList<Integer>) c.list.clone();
return c;
}
@Override
public String toString() {
return "ReTry{" +
"id='" + id + '\'' +
", list=" + list +
'}';
}
public static void main(String[] args) throws CloneNotSupportedException {
ReTry aTry = new ReTry();
ReTry clone = aTry.clone();
aTry.id=1002;//修改了基本类型
aTry.list.add(5);//修改了引用类型
System.out.println(clone);
System.out.println(aTry);
/*
ReTry{id='1001', list=[10, 5]}
ReTry{id='1002', list=[10, 5]}
*/
}
}
原对象修改了int变量后,副本的int变量没有变化。
修改了List,副本的也变化了,因为list还是引用的同一对象。
深拷贝
深拷贝不仅复制对象本身,而且复制对象包含的引用指向的所有对象.
在clone方法中,将引用变量也处理clone.
c.list= (LinkedList<Integer>) c.list.clone();
此时结果互不影响了。
ReTry{id='1001', list=[10]}
ReTry{id='1002', list=[10, 5]}