- identityHashCode永远返回根据对象物理内存地址产生的hash值
比如new出来的String 他们的hash值一样但是identityHashCode不一样 - 不可变类
不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值,也就是不能改变对象的状态。
Java 中八个基本类型的包装类和 String 类都属于不可变类,而其他的大多数类都属于可变类。
- 深拷贝
相当于创建了一个新的对象,只是这个对象的所有内容,都和被拷贝的对象一模一样而已,即两者的修改是隔离的,相互之间没有影响、完全独立
- 浅拷贝
也是创建了一个对象,但是这个对象的某些内容(比如A)依然是被拷贝对象的,即通过这两个对象中任意一个修改A,两个对象的A都会受到影响
1.类的复制
1.1 clone() 浅拷贝
需要实现Cloneable 接口的clone()方法
类本身是新的,但成员变量类不是新的,修改一个另一个也会改变,也需要clone() 才能实现深拷贝,而String和Integer由于不可变性,实际是一个值,但是修改不会互相影响
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Banana implements Serializable,Cloneable {
private Integer weight;
private String taste;
private Apple apple;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
@Data
@AllArgsConstructor
public class Apple implements Serializable,Cloneable {
private Integer weight;
private String color;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
@Test
public void cloneTest() throws Exception{
Banana source = new Banana(11,"bitter", new Apple(80,"green"));
Banana target = (Banana)source.clone();
Banana targetOne =(Banana)source.clone();
targetOne.setApple((Apple)source.getApple().clone());
System.out.println("taste:"+System.identityHashCode(source.getTaste()));
System.out.println("taste:"+System.identityHashCode(target.getTaste()));
System.out.println("taste:"+System.identityHashCode(targetOne.getTaste()));
System.out.println("apple:"+System.identityHashCode(source.getApple()));
System.out.println("apple:"+System.identityHashCode(target.getApple()));
System.out.println("apple:"+System.identityHashCode(targetOne.getApple()));
source.setTaste("sweet");
source.getApple().setColor("red");
System.out.println(source);
System.out.println(target);
System.out.println(targetOne);
}
2.2 BeanUtils 浅拷贝
同上
@Test
public void BeanUtilsTest() throws Exception{
Banana source = new Banana(80,"bitter",new Apple(12,"aaa"));
Banana copy = new Banana();
BeanUtils.copyProperties(source,copy);
System.out.println("body:"+System.identityHashCode(source));
System.out.println("body:"+System.identityHashCode(copy));
System.out.println("taste:"+System.identityHashCode(source.getTaste()));
System.out.println("taste:"+System.identityHashCode(copy.getTaste()));
System.out.println("apple:"+System.identityHashCode(source.getApple()));
System.out.println("apple:"+System.identityHashCode(copy.getApple()));
System.out.println("color:"+System.identityHashCode(source.getApple().getColor()));
System.out.println("color:"+System.identityHashCode(copy.getApple().getColor()));
source.setTaste("sweet");
source.getApple().setColor("red");
System.out.println(source);
System.out.println(copy);
}
2.3 序列化 深拷贝
只有这样才是不管包含什么变量都完全是新的不会互相影响
@Test
public void cloneSerializableTest() throws Exception{
Banana source = new Banana(11,"bitter", new Apple(80,"green"));
Banana target = deepCopy(source);
System.out.println(System.identityHashCode(source));
System.out.println(System.identityHashCode(target));
System.out.println("Apple:"+System.identityHashCode(source.getApple()));
System.out.println("Apple:"+System.identityHashCode(target.getApple()));
source.setTaste("sweet");
source.getApple().setColor("red");
System.out.println(source);
System.out.println(target);
}
public static <T> T deepCopy(T src) throws IOException, ClassNotFoundException {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(src);
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream in = new ObjectInputStream(byteIn);
@SuppressWarnings("unchecked")
T dest = (T) in.readObject();
return dest;
}
2.List的复制
另外可以注意到的是List本身的构造方法,循环复制,addAll,copy,ArrayList.clone(),甚至变成数组
都是只有壳是新的,里面的内容都是同一个
@Test
public void listObjectTest() throws Exception{
Apple source1 = new Apple(10,"green");
ArrayList<Apple> srcList= new ArrayList<>();
srcList.add(source1);
List<Apple> dest1List= new ArrayList<>();
srcList.forEach(o->dest1List.add(o));
ArrayList<Apple> dest2List = (ArrayList<Apple>)srcList.clone();
ArrayList<Apple> dest3List = new ArrayList<>(srcList);
Apple[] dest4List = srcList.toArray(new Apple[srcList.size()]);
System.out.println(System.identityHashCode(srcList.get(0)));
System.out.println(System.identityHashCode(dest1List.get(0)));
System.out.println(System.identityHashCode(dest2List.get(0)));
System.out.println(System.identityHashCode(dest3List.get(0)));
System.out.println(System.identityHashCode(dest4List[0]));
source1.setColor("red");
System.out.println(srcList);
System.out.println(dest1List);
System.out.println(dest2List);
System.out.println(dest3List);
System.out.println(dest4List[0]);
}