資料型別
Java的資料型別包括基本資料型別和引用資料型別:
基本資料型別:
-
整形:byte, short, int, long
-
浮點型:float, double
-
字元型:char
-
布林型:boolean
引用資料型別:class, interface, array。
引用複製,淺複製,深複製
引用複製
在Java中,物件的引用複製是指將一個物件的引用賦值給另一個變數。透過引用複製,兩個變數將指向同一個物件,它們共享同一塊記憶體空間。當修改其中一個變數指向的物件時,另一個變數也會受到影響。
下面是一個簡單的示例程式碼,演示了物件引用複製的概念:
public class Test {
public static void main(String[] args) {
// 建立一個Person物件
Person person1 = new Person("Alice", 25);
// 將person1的引用複製給person2
Person person2 = person1;
System.out.println("person1: " + person1);
System.out.println("person2: " + person2);
// 修改person1的屬性
person1.setName("Bob");
person1.setAge(30);
System.out.println("person1: " + person1);
System.out.println("person2: " + person2);
// True
System.out.println(person1 == person2);
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person[name=" + name + ", age=" + age + "]";
}
}
在上述程式碼中,建立了一個Person物件person1,然後將其引用複製給person2。修改person1的屬性後,列印person1和person2的值,可以發現它們指向同一個物件,因此修改person1的屬性後,person2的屬性也會相應改變。
輸出結果如下:
person1: Person[name=Alice, age=25]
person2: Person[name=Alice, age=25]
person1: Person[name=Bob, age=30]
person2: Person[name=Bob, age=30]
true
可以看到,透過引用複製,person1和person2指向同一個Person物件,修改其中一個物件的屬性會影響另一個物件。
淺複製
在Java中,淺複製(Shallow Copy)是指建立一個新物件,並將原始物件中的所有欄位的值複製到新物件中。淺複製只是簡單地複製物件的欄位值,如果物件中包含引用型別的欄位,則新物件和原始物件會共享這些引用型別的欄位。
淺複製是透過複製物件的引用來實現的,也就是說,新物件和原始物件指向了同一個記憶體地址。因此,如果修改了新物件的引用型別欄位的值,原始物件的引用型別欄位的值也會被修改,因為它們指向同一個物件。
要實現淺複製,可以使用以下幾種方式:
使用Object類的clone()
方法:Object類中的clone()方法可以複製一個物件,但它只複製物件的欄位值,不復制引用型別欄位指向的物件。因此,如果物件中包含引用型別欄位,那麼新物件和原始物件會共享這些引用型別的欄位。
使用複製建構函式:透過定義一個建構函式,引數為原始物件,將原始物件中的欄位值複製到新物件中。
需要注意的是,淺複製只是複製物件的欄位值,而不復制物件內部的引用型別欄位的值。因此,如果需要實現深複製,就需要對引用型別欄位進行遞迴複製,確保新物件和原始物件的引用型別欄位指向不同的物件。
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Address(String address) {
this.address = address;
}
}
class Person implements Cloneable {
private String name;
private int age;
private Address address;
public Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Address getAddress() {
return address;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return this.name + "-" + this.age + "-" + this.address.getAddress();
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Address address1 = new Address("山東");
Person person1 = new Person("Alice", 25, address1);
Person person2 = (Person) person1.clone();
System.out.println(person1);
System.out.println(person2);
person1.setAge(30);
address1.setAddress("上海");
System.out.println(person1);
System.out.println(person2);
//Alice-25-山東
//Alice-25-山東
//Alice-30-上海
//Alice-25-上海
}
}
深複製
在 Java 中,深複製(Deep Copy)是指建立一個新物件,將原始物件中的所有欄位的值都複製到新物件中。深複製會遞迴複製物件的所有層級,包括物件的引用型別欄位,確保新物件和原始物件完全獨立相對地,淺複製(Shallow Copy)只是簡單地複製物件的欄位值,如果物件中包含引用型別的欄位,那麼新物件和原始物件會共享這些引用型別的欄位。
為了實現深複製,可以使用以下幾種方式:
實現 Cloneable介面和覆寫 clone() 方法
:透過實現 Cloneable 介面來指明物件可以進行複製操作,並覆寫 clone() 方法來實現深複製的邏輯。
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Person person1 = new Person("Alice", 25, new Address("山東"));
Person person2 = (Person) person1.clone();
System.out.println(person1);
System.out.println(person2);
person2.setName("david");
person2.setAge(30);
person2.getAddress().setAddress("上海");
System.out.println(person1);
System.out.println(person2);
//Alice-25-山東
//Alice-25-山東
//Alice-25-山東
//david-30-上海
}
}
public class Address implements Cloneable{
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Address(String address) {
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Address clone = (Address) super.clone();
clone.setAddress(this.address);
return clone;
}
}
class Person implements Cloneable {
private String name;
private int age;
private Address address;
public Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
public Person() {
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Address getAddress() {
return address;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return this.name + "-" + this.age + "-" + this.address.getAddress();
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person res = (Person) super.clone();
res.address = (Address) this.address.clone();
return res;
}
}
使用序列化和反序列化:透過將物件序列化為字流,再將位元組流反序列化為新物件來實現深複製。
public class MyClass implements Serializable {
private int value;
private MyObject obj;
// 建構函式和其他方法
public MyClass deepCopy() throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this); // 序列化當前物件
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (MyClass) ois.readObject(); // 反序列化生成新物件
}
}
需要注意的是,為了現深複製,不僅僅需要複製物件本身,還需要複製物件內部的引用型別欄位。因此,如果引用型別欄位也需要支援深複製,那麼該引用型別也需要實現 Cloneable 介面或者序列化介面,並在複製方法中進行遞迴拷。
淺複製和深複製的區別
在Java中,淺複製(Shallow Copy)和深複製(Deep Copy)是兩種不同的物件複製方式,它們的主要區別如下:
- 複製的內容不同:
- 淺複製只複製物件的欄位值,不復制引用型別欄位指向的物件。
- 深複製會遞迴複製物件的所有層級,包括物件的引用型別欄位。
- 物件的獨立性不同:
- 淺複製複製後的物件與原始物件共享相同的引用型別欄位,即它們指向相同的物件。
- 深複製複製後的物件與原始物件完全獨立,它們的引用型別欄位指向不同的物件。
- 物件修改的影響不同:
- 淺複製中,如果修改新物件的引用型別欄位的值,原始物件的相應欄位也會被修改,因為它們指向同一個物件。
- 深複製中,修改新物件的引用型別欄位的值不會影響原始物件的相應欄位,因為它們指向不同的物件。
- 實現方式不同:
- 淺複製可以透過
Object類的clone()
方法、複製建構函式等方式實現。 - 深複製需要對物件的引用型別欄位進行遞迴複製,可以透過實現Cloneable介面和覆蓋clone()方法、使用序列化和反序列化等方式實現。
- 淺複製可以透過
總結來說,淺複製只複製物件的欄位值,不復制引用型別欄位指向的物件,而深複製會遞迴複製所有層級的物件,確保新物件和原始物件完全獨立。因此,深複製相比淺複製更加安全,但也需要更多的資源和效能開銷。選擇使用哪種複製方式,需要根據具體的場景和需求來決定。