欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java四種拷貝方式實(shí)戰(zhàn)總結(jié)(一文掃清所有拷貝問題)

 更新時(shí)間:2025年07月11日 10:43:10   作者:小W求學(xué)之旅  
在Java中文件拷貝可以通過多種方式實(shí)現(xiàn),不同方式的性能和適用場(chǎng)景有所差異,文中通過代碼介紹的非常詳細(xì),這篇文章主要介紹了Java四種拷貝方式的相關(guān)資料,需要的朋友可以參考下

前言

作為Java開發(fā)者,日常開發(fā)中經(jīng)常會(huì)遇到數(shù)據(jù)拷貝的需求。最近在面試中也有被問到一次大文件拷貝,抽空專門總結(jié)一下,從基礎(chǔ)概念到實(shí)戰(zhàn)技巧,配合流程圖,讓原理和流程一目了然~

一、淺拷貝VS深拷貝

一開始做spring項(xiàng)目時(shí),就被淺拷貝坑過。當(dāng)時(shí)想復(fù)制一個(gè)對(duì)象,結(jié)果改了新對(duì)象的屬性,老對(duì)象也跟著變了。后來才知道,這就是淺拷貝的“鍋”。

淺拷貝就像拍證件照,照片上的人看著和你一模一樣,但本質(zhì)上還是兩張紙。Java里的淺拷貝只會(huì)復(fù)制對(duì)象的基本屬性,遇到引用類型(比如自定義類),就直接把地址抄過來。所以你改新對(duì)象里的引用屬性,老對(duì)象也會(huì)跟著遭殃。

深拷貝就靠譜多了,它會(huì)把對(duì)象里里外外都復(fù)制一遍,就像克隆人,新對(duì)象和老對(duì)象完全獨(dú)立。雖然麻煩點(diǎn),但勝在安全,適合處理復(fù)雜對(duì)象。

舉個(gè)例子,有個(gè)Person類包含nameAddress屬性:

class Address {
    String city;
}

class Person {
    String name;
    Address address;

    // 淺拷貝
    Person shallowCopy() {
        Person copy = new Person();
        copy.name = this.name;
        copy.address = this.address;
        return copy;
    }

    // 深拷貝
    Person deepCopy() {
        Person copy = new Person();
        copy.name = this.name;
        copy.address = new Address();
        copy.address.city = this.address.city;
        return copy;
    }
}

二、大文件拷貝:別讓你的程序“龜速運(yùn)行”

之前做文件上傳功能,用傳統(tǒng)IO方式拷貝大文件,結(jié)果服務(wù)器直接卡住。后來?yè)Q成NIO,速度直接起飛!

傳統(tǒng)IO就像螞蟻搬家,一次搬一點(diǎn),頻繁讀寫磁盤;NIO則像卡車運(yùn)輸,直接把數(shù)據(jù)從一個(gè)地方搬到另一個(gè)地方,速度快得多。

// 傳統(tǒng)IO方式,適合小文件
public static void copyFileByIO(File source, File dest) throws IOException {
    try (InputStream is = new FileInputStream(source);
         OutputStream os = new FileOutputStream(dest)) {
        byte[] buffer = new byte[1024];
        int len;
        while ((len = is.read(buffer)) != -1) {
            os.write(buffer, 0, len);
        }
    }
}

// NIO方式,適合大文件
public static void copyFileByNIO(File source, File dest) throws IOException {
    try (FileChannel sourceChannel = new FileInputStream(source).getChannel();
         FileChannel destChannel = new FileOutputStream(dest).getChannel()) {
        destChannel.transferFrom(sourceChannel, 0, sourceChannel.size());
    }
}

三、對(duì)象拷貝的進(jìn)階方案:使用造好的輪子

手動(dòng)寫深拷貝代碼太麻煩?別慌,Java提供給我們有不少寫好的辦法。

1. 序列化與反序列化

就像把對(duì)象打包成快遞,寄出去再拆開。雖然速度慢點(diǎn),但能保證完全獨(dú)立的拷貝。不過要注意,所有相關(guān)類都得實(shí)現(xiàn)Serializable接口。

public static <T extends Serializable> T deepCopyBySerialization(T obj) {
    try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
         ObjectOutputStream oos = new ObjectOutputStream(baos)) {
        oos.writeObject(obj);
        try (ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
             ObjectInputStream ois = new ObjectInputStream(bais)) {
            return (T) ois.readObject();
        }
    } catch (IOException | ClassNotFoundException e) {
        throw new RuntimeException(e);
    }
}

2. JSON序列化

用Jackson或Gson把對(duì)象轉(zhuǎn)成JSON字符串,再轉(zhuǎn)回來,簡(jiǎn)單粗暴。不過這種方式要求對(duì)象的屬性都能被JSON正確解析。

import com.fasterxml.jackson.databind.ObjectMapper;

public static <T> T deepCopyByJSON(T obj, Class<T> clazz) {
    try {
        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writeValueAsString(obj);
        return mapper.readValue(json, clazz);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

四、數(shù)組和集合的拷貝

數(shù)組的clone()方法看似簡(jiǎn)單,實(shí)則暗藏玄機(jī):基本類型數(shù)組用它是深拷貝,對(duì)象數(shù)組就是淺拷貝。

int[] intArray = {1, 2, 3};
int[] copiedIntArray = intArray.clone(); // 深拷貝

Person[] personArray = new Person[2];
Person[] copiedPersonArray = personArray.clone(); // 淺拷貝

集合類的構(gòu)造函數(shù)也是淺拷貝,比如new ArrayList<>(originalList)。想深拷貝集合,得手動(dòng)遍歷每個(gè)元素。

List<Person> originalList = new ArrayList<>();
List<Person> deepCopiedList = originalList.stream()
        .map(Person::deepCopy)
        .collect(Collectors.toList());

五、第三方庫(kù):站在巨人的肩膀上

不想自己造輪子?Apache Commons Lang和Dozer能幫你大忙。前者提供了便捷的序列化拷貝工具,后者擅長(zhǎng)對(duì)象屬性映射,用起來超方便。

<!-- Apache Commons Lang依賴 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>

// 使用示例
Person copiedPerson = SerializationUtils.clone(originalPerson);

六、總結(jié):看不同場(chǎng)景選擇合適的拷貝方式

  • 簡(jiǎn)單對(duì)象用淺拷貝,復(fù)雜對(duì)象用深拷貝
  • 大文件優(yōu)先用NIO,小文件用傳統(tǒng)IO
  • 能偷懶就偷懶,善用第三方庫(kù)
  • 多寫測(cè)試用例,別讓拷貝“埋雷”

到此這篇關(guān)于Java四種拷貝方式實(shí)戰(zhàn)文章就介紹到這了,更多相關(guān)Java四種拷貝方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 關(guān)于BindingResult的使用總結(jié)及注意事項(xiàng)

    關(guān)于BindingResult的使用總結(jié)及注意事項(xiàng)

    這篇文章主要介紹了關(guān)于BindingResult的使用總結(jié)及注意事項(xiàng),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java多個(gè)線程同時(shí)執(zhí)行的方法

    Java多個(gè)線程同時(shí)執(zhí)行的方法

    這篇文章主要介紹了Java多線程處理文件詳解與代碼示例,通過本文的介紹和代碼示例,我們了解了如何使用Java多線程來處理文件,使用多線程技術(shù)可以顯著提高文件處理的效率,特別是對(duì)于大量文件的處理任務(wù),需要的朋友可以參考下
    2024-12-12
  • SpringBoot中配置Redis連接池的完整指南

    SpringBoot中配置Redis連接池的完整指南

    這篇文章主要為大家詳細(xì)介紹了SpringBoot中配置Redis連接池的完整指南,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-04-04
  • 哲學(xué)家就餐問題中的JAVA多線程學(xué)習(xí)

    哲學(xué)家就餐問題中的JAVA多線程學(xué)習(xí)

    哲學(xué)家就餐問題是1965年由Dijkstra提出的一種線程同步的問題,下面我們就看一下JAVA多線程如何做
    2013-11-11
  • Springboot 2.x集成kafka 2.2.0的示例代碼

    Springboot 2.x集成kafka 2.2.0的示例代碼

    kafka近幾年更新非??欤部梢钥闯鰇afka在企業(yè)中是用的頻率越來越高。本文主要為大家介紹了Springboot 2.x集成kafka 2.2.0的示例代碼,需要的可以參考一下
    2022-04-04
  • java ExecutorService CompletionService線程池區(qū)別與選擇

    java ExecutorService CompletionService線程池區(qū)別與選擇

    這篇文章主要為大家介紹了java ExecutorService CompletionService線程池區(qū)別與選擇使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • springcloud gateway設(shè)置context-path的操作

    springcloud gateway設(shè)置context-path的操作

    這篇文章主要介紹了springcloud gateway設(shè)置context-path的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java使用迭代器Iterator遍歷集合

    Java使用迭代器Iterator遍歷集合

    Iterator對(duì)象稱為迭代器(設(shè)計(jì)模式的一種),主要用于遍歷 Collection 集合中的元素。本文就來和大家詳細(xì)聊聊Java如何使用迭代器Iterator實(shí)現(xiàn)遍歷集合,感興趣的可以跟隨小編一起學(xué)習(xí)一下
    2022-12-12
  • SpringBoot中給指定接口加上權(quán)限校驗(yàn)的實(shí)現(xiàn)

    SpringBoot中給指定接口加上權(quán)限校驗(yàn)的實(shí)現(xiàn)

    本文介紹了使用SpringSecurity為接口添加權(quán)限校驗(yàn),以防止外部訪問并確保安全性,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-12-12
  • SpringBoot整合Activiti工作流框架的使用

    SpringBoot整合Activiti工作流框架的使用

    本文主要介紹了SpringBoot整合Activiti工作流框架的使用,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02

最新評(píng)論