一:Java中創(chuàng)建對(duì)象的方式
1:使用new操作符創(chuàng)建對(duì)象。
2:使用clone()復(fù)制對(duì)象。
3:使用反序列化來(lái)創(chuàng)建對(duì)象。
4:反射機(jī)制創(chuàng)建對(duì)象。
5:Unsafe.allocateInstance()創(chuàng)建對(duì)象。
示例
/**
* <p>
* Java中創(chuàng)建對(duì)象的方式
* </p>
* @author: zhu.chen
* @date: 2020/7/27
* @version: v1.0.0
*/
public class CreateObjectTest {
public static void main(String[] args) throws CloneNotSupportedException, IllegalAccessException, InstantiationException, IOException, ClassNotFoundException {
// 1:通過(guò)new創(chuàng)建對(duì)象
Person newPerson = new Person("zhangsan", 1);
System.out.println(newPerson);
// 2:通過(guò)clone():屬性需要實(shí)現(xiàn)Cloneable接口,并重寫(xiě)Object類的clone()。
Person clonePerson = (Person) newPerson.clone();
System.out.println(clonePerson);
// 3:通過(guò)序列化和反序列化:需要實(shí)現(xiàn)序列化接口Serializable
Person serializablePerson = serializablePerson();
System.out.println(serializablePerson);
// 4:通過(guò)反射創(chuàng)建對(duì)象:通過(guò)newInstance()來(lái)創(chuàng)建時(shí),必須有無(wú)參構(gòu)造函數(shù)。
Class clazz = Person.class;
Person reflectionPerson = (Person) clazz.newInstance();
reflectionPerson.setAge(2);
reflectionPerson.setName("xiaoming");
System.out.println(reflectionPerson);
// 5:Unsafe.allocateInstance
Person unsafePerson = (Person) unsafe.allocateInstance(Person.class);
unsafePerson.setName("xiaobai");
unsafePerson.setAge(5);
System.out.println(unsafePerson);
// 6:BeanUtils的拷貝
Person beanPerson = new Person();
BeanUtils.copyProperties(newPerson, beanPerson);
System.out.println(beanPerson);
}
/**
* 獲取unsafe類
*/
static Unsafe unsafe;
static {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe = (Unsafe) field.get(null);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 序列化對(duì)象
*
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
private static Person serializablePerson() throws IOException, ClassNotFoundException {
/**
* 網(wǎng)絡(luò)傳輸和磁盤(pán)IO會(huì)存在序列化對(duì)象來(lái)進(jìn)行傳輸和存儲(chǔ)。
* 適用場(chǎng)景:IO(網(wǎng)絡(luò)IO、磁盤(pán)IO)
*/
// 序列化
Person person = new Person("xiaohong", 4);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"));
oos.writeObject(person);
// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.txt"));
return (Person) ois.readObject();
}
private static class Person implements Cloneable, Serializable {
private static final long serialVersionUID = -5463972443328267182L;
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = 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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
}
注:同步更新于CreateObjectTest
二:Java的深淺拷貝
淺拷貝:如果屬性是基本類型,拷貝的就是基本類型的值;如果屬性是內(nèi)存地址(引用類型),拷貝的就是內(nèi)存地址。
深拷貝:深拷貝會(huì)拷貝所有的屬性,并拷貝屬性指向的動(dòng)態(tài)分配的內(nèi)存。

深淺拷貝.png
1:使用new操作符創(chuàng)建對(duì)象:深拷貝
2:使用clone()復(fù)制對(duì)象:深拷貝、淺拷貝(具體看寫(xiě)法)
3:使用反序列化來(lái)創(chuàng)建對(duì)象:深拷貝
4:反射機(jī)制創(chuàng)建對(duì)象:深拷貝
5:Unsafe.allocateInstance()創(chuàng)建對(duì)象:深拷貝
三:如何選擇拷貝方式
對(duì)象的拷貝一般都是用第三方工具類實(shí)現(xiàn),比如spring-beans中的BeanUtils#copyProperties。
1:如果對(duì)象的屬性全是基本類型的,那么可以使用淺拷貝。
2:如果對(duì)象有引用屬性,那就要基于具體的需求來(lái)選擇淺拷貝還是深拷貝。如果對(duì)象引用任何時(shí)候都不會(huì)被改變,那么沒(méi)必要使用深拷貝,只需要使用淺拷貝就行了。如果對(duì)象引用經(jīng)常改變,那么就要使用深拷貝。