首頁 Java java教程 java序列化存取實現物件克隆的實例詳解

java序列化存取實現物件克隆的實例詳解

Apr 26, 2017 am 10:05 AM
存取 序列化

本篇文章是對序列化訪問實現java物件深度克隆的方法進行了詳細的分析介紹,需要的朋友參考下

我們知道,在java中,將一個非原型類型類型的物件引用,賦值給另一個物件的引用之後,這兩個引用就指向了同一個對象,如:

 程式碼如下:

public class DeepCloneTest { private class CloneTest {  private Long myLong = new Long(1); } public static void main(String args[]) {  new DeepCloneTest().Test(); } public void Test() {  CloneTest ct1 = new CloneTest();  CloneTest ct2 = ct1;  // to see if ct1 and ct2 are one same reference.  System.out.println("ct1: " + ct1);  System.out.println("ct2: " + ct2);  // if ct1 and ct2 point to one same object, then ct1.myLong == ct2.myLong.  System.out.println("ct1.myLong: " + ct1.myLong);  System.out.println("ct2.myLong: " + ct2.myLong);  // we change ct2's myLong  ct2.myLong = 2L;  // to see whether ct1's myLong was changed.  System.out.println("ct1.myLong: " + ct1.myLong);  System.out.println("ct2.myLong: " + ct2.myLong); }}
登入後複製

out put:
ct1: DeepCloneTest$CloneTest@c17164
ct2: DeepCloneTest$CloneTest@c17164
ct1.myLong: 1
ct2.myLong: 1
ct1.myLong: 2
ct2.myLong: #2.
這個很easy,估計學java的都知道(不知道的是學java的麼?)。
在記憶體中,物件的參考存放在堆疊中,物件的數據,存放在堆中,堆疊中的參考指向了堆中的物件。這裡就是兩個堆疊中的引用,指向了堆中的同一個對象,所以,當改變了ct2 的myLong,可以看到,ct1 的myLong 值也隨之改變,如果用圖來表示,就很容易理解了:

java序列化存取實現物件克隆的實例詳解

左邊的是堆疊區,該區中有兩個引用,值相同,它們指向了右邊堆區的同一個對象。
大多時候,我們會用 java 語言的這一特性做我們想做的事情,比如,將物件的引用作為入參傳入一個方法中,在方法中,對引用所指物件做相應修改。但有時,我們希望建構出一個和已經存在的對象具有完全相同的內容,但引用不同的對象,為此,可以這樣做

 代碼如下:

public class DeepCloneTest{ // must implements Cloneable. private class CloneTest implements Cloneable{  private Object o = new Object();  public CloneTest clone() {   CloneTest ct = null;   try {    ct = (CloneTest)super.clone();   } catch (CloneNotSupportedException e) {    e.printStackTrace();   }   return ct;  } } public static void main(String args[]) {  new DeepCloneTest().Test(); } public void Test() {  CloneTest ct1 = new CloneTest();  CloneTest ct2 = ct1.clone();  // to see if ct1 and ct2 are one same reference.  System.out.println("ct1: " + ct1);  System.out.println("ct2: " + ct2);  // whether ct1.o == ct2.o ? yes  System.out.println("ct1.o " + ct1.o);  System.out.println("ct1.o " + ct1.o); }}
登入後複製

out put:
ct1: DeepCloneTest$CloneTest@c17164
ct2: DeepCloneTest$CloneTest@1fb8ee3
ct1.o java.lang.Object@61de33
1.o java .lang.Object@61de33
從輸出可以看出:ct1 和ct2 確實是兩個不同的引用,所以我們想當然的認為,ct1.o 和ct2.o 也是兩個不同的物件了,但從輸出可以看出並非如此! ct1.o 和 ct2.o 是同一個物件!原因在於,雖然用到了克隆,上面只是淺度克隆,用圖形來表示:

java序列化存取實現物件克隆的實例詳解
看到上面的 o 了麼?其實是兩個物件共享的。這就相當於,你本來有一個羊圈1,裡面有一隻羊,然後你又弄了一個羊圈2,在不將羊從羊圈1裡牽出來的情況下,將羊也圈在了羊圈2中,你以為你有兩隻羊了,其實呢?大家都知道。

這就是淺度克隆的結果:如果你想讓兩個物件有獨立的 o,就必須再對 o 做複製運算。可能有些人認為這沒有什麼,做就做唄,但想過沒有,如果不止一個 o, 還有很多很多的類似 o 的東東,你都逐一去做克隆嗎?顯然是不太現實的。

一種解決方法是:將物件先序列化儲存到流中,然後再從留中讀出對象,這樣就可以保證讀取出來的資料和之前的對象,裡面的數值完全相同,就像是完全的拷貝。

 程式碼如下:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class DeepCloneTest {
 // must implements Cloneable.
 private class CloneTest implements Serializable{
  private static final long serialVersionUID = 1L;
  private Object o = new Object();
  public CloneTest deepClone() {
   CloneTest ct = null;
   try {
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
             ObjectOutputStream oos = new ObjectOutputStream(baos); 
             oos.writeObject(this);
             ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 
             ObjectInputStream ois= new ObjectInputStream(bais); 
             ct = (CloneTest)ois.readObject(); 
   } catch (IOException e) {
    e.printStackTrace();
   } catch (ClassNotFoundException e) {
    e.printStackTrace();
   }
   return ct;
  }
 }
 public static void main(String args[]) {
  new DeepCloneTest().Test();
 }
 public void Test() {
  CloneTest ct1 = new CloneTest();
  CloneTest ct2 = ct1.deepClone();
  // to see if ct1 and ct2 are one same reference.
  System.out.println("ct1: " + ct1);
  System.out.println("ct2: " + ct2);
  // whether ct1.o == ct2.o ? no
  System.out.println("ct1.o " + ct1.o);
  System.out.println("ct1.o " + ct1.o);
 }
}
登入後複製


這個時候,記憶體中的資料就是這樣的了:

java序列化存取實現物件克隆的實例詳解

##克隆任務完成。

以上是java序列化存取實現物件克隆的實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1677
14
CakePHP 教程
1431
52
Laravel 教程
1334
25
PHP教程
1280
29
C# 教程
1257
24
PHP資料處理技巧:如何使用serialize與unserialize函數實作資料序列化與反序列化 PHP資料處理技巧:如何使用serialize與unserialize函數實作資料序列化與反序列化 Jul 29, 2023 am 10:49 AM

PHP資料處理技巧:如何使用serialize和unserialize函數實現資料序列化與反序列化序列化和反序列化是電腦科學中常用的資料處理技巧之一。在PHP中,我們可以使用serialize()和unserialize()函數來實現資料的序列化和反序列化操作。本文將為您詳細介紹如何使用這兩個函數,並提供相關程式碼範例。一、什麼是序列化和反序列化在電腦編

在Java中,我們如何使用flexjson序列化物件清單? 在Java中,我們如何使用flexjson序列化物件清單? Sep 05, 2023 pm 11:09 PM

Flexjson是一個輕量級函式庫,用於序列化和反序列化Java物件>和來自JSON格式。我們可以使用JSONSerializer類別的serialize()方法序列化物件清單。此方法可以對目標實例執行淺層序列化。我們需要將清單類型的物件清單作為參數傳遞給serialize()方法。語法publicStringserialize(Objecttarget)範例importflexjson.JSONSerializer;importjava.util.*;publicclassJsonSerial

C++ 函式庫如何進行序列化與反序列化? C++ 函式庫如何進行序列化與反序列化? Apr 18, 2024 am 10:06 AM

C++函式庫序列化和反序列化指南序列化:建立輸出流並將其轉換為存檔格式。將物件序列化到存檔中。反序列化:建立輸入流並將其從存檔格式還原。從存檔中反序列化物件。實戰範例:序列化:建立輸出流。建立存檔物件。建立物件並將其序列化到存檔中。反序列化:建立輸入流。建立存檔物件。建立物件並從存檔中反序列化。

如何使用 PHP 實現資料快取和讀寫功能 如何使用 PHP 實現資料快取和讀寫功能 Sep 05, 2023 pm 05:45 PM

如何使用PHP實現資料快取和讀寫功能快取是提高系統效能的重要方式,透過快取可以將頻繁使用的資料儲存在記憶體中,以提高資料的讀取速度。在PHP中,我們可以使用各種方法來實現資料快取和讀寫功能。本文將介紹兩種常用的方法:使用檔案快取和使用記憶體快取。一、使用檔案快取檔案快取是將資料儲存在檔案中,以便後續讀取。下面是一個使用檔案快取實現資料讀寫的範例程式碼:

Java序列化如何影響效能? Java序列化如何影響效能? Apr 16, 2024 pm 06:36 PM

序列化对Java性能的影响:序列化过程依赖于反射,会显著影响性能。序列化需要创建字节流存储对象数据,导致内存分配和处理成本。序列化大对象会消耗大量内存和时间。序列化后的对象在网络上传输时会增加负载量。

如何使用Java中的Jackson函式庫對屬性的順序進行序列化? 如何使用Java中的Jackson函式庫對屬性的順序進行序列化? Aug 28, 2023 pm 12:45 PM

@JsonPropertyOrder是在類別層級使用的註解。它採用字段列表作為屬性,該列表定義字段在物件JSON序列化生成的字串中出現的順序。可以先序列化註釋聲明中包含的屬性(按定義的順序),然後序列化定義中未包含的任何屬性。語法public@interfaceJsonPropertyOrder範例importcom.fasterxml.jackson.core.*;importcom.fasterxml.jackson.databind.*;importcom.fasterxml.jac

Java 中介面和抽象類別的序列化和反序列化 Java 中介面和抽象類別的序列化和反序列化 May 02, 2024 am 08:33 AM

介面無法直接序列化,抽象類別可以序列化但前提是不包含非靜態、非瞬態欄位或覆寫writeObject()和readObject()方法,具體實例可透過實作介面的具體類別或覆寫writeObject()和readObject ()方法的抽象類別實作。

golang函數類型的序列化與反序列化 golang函數類型的序列化與反序列化 Apr 29, 2024 am 08:15 AM

GoLang函數類型可透過encoding/gob套件實現序列化和反序列化。序列化:註冊自訂類型並使用gob.NewEncoder將函數類型編碼為位元組數組。反序列化:使用gob.NewDecoder從位元組數組反序列化函數類型。

See all articles