阿里Java開發規約為什麼不建議使用Apache BeanUtils拷貝對象?

2020-12-09 計算機java編程

前言

做 JAVA 開發的同學都知道,在 JAVA 世界中萬事萬物皆為對象。是我們在實際開發中,經常會遇到將一個對象實例拷貝轉換為另一個對象實例的情況:對兩個對象的屬性進行淺(深)度複製。

舉個例子:

在 controller 中接收前端傳遞的參數的實體定義為以 Args結尾的類,然後我們在調用 service 層的接口,但是 service 中的接口參數是以 DTO 結尾的類型,這時候就需要將 Args 類對象屬性拷貝到 DTO 類對象上,由於對象的類型是不一樣的,所以我們需要編寫映射代碼將源對象的屬性值從一種類型轉換為另一種類型。

在具體介紹 BeanUtils 工具以前,先介紹一個有關拷貝的基礎知識。其實所有的 BeanUtils本質上就是對象拷貝工具,通常對象拷貝分為:深拷貝和淺拷貝,接下來做詳細解釋。

什麼是淺拷貝和深拷貝

在 JAVA 中除了 char、byte、short、int、long、float、double、boolean等基礎類型之外,還有類實例對象的引用數據類型。

一般使用"="做賦值操作,對於基本數據類型,實際上是拷貝的它的值,對於對象而言,賦值的實際上是這個對象的引用,將源對象的引用傳遞過去,本質上還是指向同一個對象。

通常說的淺拷貝和深拷貝就是在這個基礎上來做區分的。那麼什麼是深拷貝,什麼是淺拷貝呢?

如果在拷貝這個對象的時候,只對基本數據類型進行了拷貝,而對引用數據類型只是進行引用的傳遞,而沒有真實的創建一個新的對象,即為淺拷貝。

反之,在對引用數據類型進行拷貝的時候,創建了一個新的對象,並且複製其內的成員變量,即為深拷貝。

簡單來說:

淺拷貝:針對基本數據類型進行值傳遞,針對引用類型進行引用傳遞的拷貝即為淺拷貝深拷貝:針對基本數據類型進行值傳遞,針對引用數據類型,先創建新的對象實例,並複製其內容,即為深拷貝。

BeanUtils

前面介紹了關於拷貝的一些基礎知識,相信大家已經有所了解,下面就進行本文的主題,具體來分析一下Apache BeanUtils 和 Spring BeanUtils這兩種 BeanUtils 工具的實現和性能。

Apache 的 BeanUtils

先給出一個簡單的使用實例,代碼如下:

從上面的例子可以看出,BeanUtils工具的使用非常簡單,最常用的方法就是:

默認情況下,使用org.apache.commons.beanutils.BeanUtils對複雜對象是進行的淺拷貝,但是由於 Apache下的BeanUtils對象拷貝性能太差,不建議使用,這在阿里巴巴Java開發規約插件上也明確指出:

Ali-Check | 避免用Apache Beanutils進行屬性的copy。

到這裡你可能會疑惑,為什麼會出現拷貝性能差的情況呢?

因為在對對象進行拷貝的時候添加很多的校驗,比如像類型轉換,甚至還校驗了對象所屬類的訪問權限,可以說校驗是相當的複雜,這也就是造成性能差的根本原因,我們看下它的具體代碼實現:

Spring 的 BeanUtils

還是老規則,先給出使用實例:

從上面的實例可以看出上 Apache 的 BeanUtils 工具的使用方式基本一直,非常簡單。

Spring下的BeanUtils也是使用 copyProperties方法進行拷貝,不過實現的方式相對於前者要來得簡單得多了,可以說是非常的簡單,就是根據兩個對象屬性的名字進行匹配,做簡單的 get/set,僅檢查屬性的可訪問性。具體實現如下:

從上面的實現源碼可以看到:成員變量賦值是基於目標對象的成員列表,並且會跳過ignore以及在源對象中不存在的屬性,所以這個方法是安全的,不會因為兩個對象之間的結構差異導致錯誤,但是必須保證同名的兩個成員變量類型相同

小結

以上簡要的分析兩種BeanUtils的具體實現以及性能相關的分析,得出結論:Apache下的BeanUtils由於各種繁瑣的校驗以及可訪問性的校驗等等,導致性能較差,故實際開發中不建議使用,可以使用 Spring的BeanUtils ,或者使用其他拷貝框架進行替代,比如:Dozer、ModelMapper等等。

相關焦點

  • 談談 Java 開發中的對象拷貝
    在Java開發工作中,有很多時候我們需要將不同的兩個對象實例進行屬性複製,從而基於源對象的屬性信息進行後續操作,而不改變源對象的屬性信息。
  • 《阿里巴巴Java開發規約》插件全球首發!
    經過247天的持續研發,阿里巴巴於10月14日在杭州雲棲大會上,正式發布眾所期待的《阿里巴巴Java開發規約》掃描插件!插件全球首發儀式,大牛雲集這個項目組是阿里巴巴開發愛好者自發組織形成的虛擬項目組,把《阿里巴巴Java開發規約》強制條目轉化成自動化插件,並實現部分的自動編程。插件下載地址:https://github.com/alibaba/p3c 或者在Github直接搜索p3c插件有哪些功能?
  • 為什麼阿里巴巴Java開發手冊強制整型包裝類對象值用equals比較?
    在閱讀《阿里巴巴Java開發手冊》時,發現有一條關於整型包裝類對象之間值比較的規約,具體內容如下:這條建議非常值得大家關注, 而且該問題在 Java 面試中十分常見。還需要思考以下幾個問題:如果不看《阿里巴巴Java開發手冊》,如何知道 Integer var = ? 會緩存 -128 到 127 之間的賦值?為什麼會緩存這個範圍的賦值?
  • eclipse離線安裝sonarlink和阿里規約插件提高代碼質量
    java程式設計師應該知道阿里規約吧,我們在寫代碼的時候應該遵循規約來提高我們的代碼質量。阿里規約不僅只有文檔,還有配合IDE使用的插件。在線安裝方式很簡單,在網上搜到的大部分也都是在線安裝的,在這裡我只記錄下離線安裝,因為有時候網絡原因,在線安裝並不是那麼簡單。
  • 每日一課 | Apache POI –用Java讀寫Excel文件
    Apache POI庫–編寫簡單的Excel以下代碼顯示了如何使用Apache POI庫編寫一個簡單的Excel文件。該代碼使用二維數據數組來保存數據。數據被寫入XSSFWorkbook對象。XSSFSheet是正在處理的工作表。
  • 排名Top 16的Java實用類庫
    當然,這些方法實現的功能我們自己都能實現,但是既然已經有很成熟的方法可以供我們使用了,那麼就無需自己定義了。很多類和方法通過他們的名字其實可以理解出具體是做什麼的。每個方法都有一個連結,可以查看他們在開原始碼中具體是如何使用的。(由於微信限制,無法增加連結,請進入原文查看)以下列表是通過分析50K的開源項目得出來的。
  • 十萬閱讀技術博主深入挖掘阿里開發思維Java開發手冊靈魂十三問
    目錄《新版Java開發手冊》提到的三目運算符的空指針問題到底是個怎麼回事4為什麼阿里巴巴建議初始化HashMap的容量大小?15Java開發手冊建議創建HashMap時設置初始化容量,但是多少合適呢?27為什麼阿里巴巴禁止使用Executors創建線程池?
  • Java開發人員必須掌握的Linux命令-學以致用(五)
    使用不當,可能就要跑路嘍!:# 1.直接敲命令刪除日誌文件[aflyun@localhost ~]$ rm -rf / home/aflyun/logs/# 看出什麼 端倪了沒有。提示一下:一定不要拷貝這條命令去執行!!!# 如果你真的好奇,那建議在自己的虛擬機上試試,滿足一下你的好奇心。
  • Java 拷貝,你能說出個 123 麼?
    而反序列化則是把磁碟文件中的對象數據或者把網絡節點上的對象數據,恢復成Java對象模型的過程。Java 基本複製方法java賦值是複製對象引用,如果我們想要得到一個對象的==副本==,使用賦值操作是無法達到目的的:修改新對象的值會同時修改舊對象的值。
  • 最受歡迎的 Java Web 開發框架盤點
    / 另外還有一些Java框架也很受歡迎,但不適用於Web開發,我們不應該忘了它們: 1)Hibernate以數據為中心。網址:http://ant.apache.org/,https://ant.apache.org/ivy/ Spring 框架 Spring 框架官方網址:https://www.spring.io/。 主要開發贊助商:Privotal 軟體公司。
  • Deepin開發真香!Java開發環境全套安裝及配置圖文教程
    如果你使用的是IDEA 2020,則可以使用IDEA自身下載並配置的JDK。但我還是一如既往的配置自己的JDK環境,這至少需要做四件事情:下載、安裝、配置和驗證。1.1 下載JDK訪問JDK的官方下載網站,在下載列表中選擇對應的JDK版本以及作業系統,點擊下載連結並下載,以JDK 8為例,下載頁面地址如下:https://www.oracle.com/java/technologies/javase/javase8u211-later-archive-downloads.html
  • java和php在web開發方面對比分析
    語法和c語言比較象,所以學過c語言的程式設計師可以很快的熟悉php的開發。而java需要先學好java的語法和熟悉一些核心的類庫,懂得面向對象的程序設計方法。所以java不如php好學。java首先要編譯成字節碼.class文件,然後在java虛擬機上解釋執行。
  • Java開發必須要知道的知識體系
    Java是超高人氣程式語言,擁有跨平臺、面向對象、泛型編程等特性。
  • 五分鐘學會 Java 開發效率神器 Lombok
    時,整片都是痛苦的紅字Lombok 用法lombok 官網提供了許多註解,但是「勁酒雖好,可不能貪杯」,你用了越多 lombok 的進階用法,會讓整個團隊的學習曲線上升,反而會造成反效果,所以在此處只解釋最最常見、並且我認為最必要的註解使用方式,其他的用法就不介紹了
  • RocketMQ 社區行為規約2.0發布!
    <body>: 對Commit更改簡短的描述,需要注意以下幾點:使用動賓結構,注意使用現在時,比如使用change 而非 changed 或 changesfeat(client): simplify pull consumer implementationrefactor(*): polish 'No route info of this topic' exceptiondocs
  • 為什麼阿里巴巴要求謹慎使用ArrayList中的subList方法
    集合是Java開發日常開發中經常會使用到的。在之前的一些文章中,我們介紹過一些關於使用集合類應該注意的事項,如《為什麼阿里巴巴禁止在 foreach 循環裡進行元素的 remove/add 操作》、《為什麼阿里巴巴建議集合初始化時,指定集合容量大小》等。
  • 2017年排名Top 100的Java類庫——在分析了259,885份源碼之後得出的結論
    譯者註:Mockito 是一個強大的用於 Java 開發的模擬測試框架, 通過 Mockito 我們可以創建和配置 Mock 對象, 進而簡化有外部依賴的類的測試.Java中的日誌組建 slf4j 位列第五。這從某個側面體現出目前的開發人員對日誌還是比較情有獨鐘的。同時也看得出Java開發人員對於 java.util.logging 庫的使用率較低。
  • 開發崗位這麼多,為什麼選Java?你學Java了嗎-開課吧
    零基礎學Java主流開發語言根據最新2020年TIOBE程式語言指數排行榜,Java仍然排名前三位。軟體開發可以使用的語法是非常多,但是為什麼Java被廣泛的使用呢?其他程式語言與Java相比,Java語法相對簡單,並且是很多計算機語言的基礎。提到C++語言,很多人發現在使用過程中最容易出現的錯誤就是內存管理,而java有自動垃圾回收器,不用擔心內存。
  • 什麼是Java深淺拷貝?
    拷貝與Java內存結構息息相關,搞懂Java深淺拷貝是很必要的!在對象的拷貝中,很多初學者可能搞不清到底是拷貝了引用還是拷貝了對象。在拷貝中這裡就分為引用拷貝、淺拷貝、深拷貝進行講述。引用拷貝引用拷貝會生成一個新的對象引用地址,但是兩個最終指向依然是同一個對象。如何更好的理解引用拷貝呢?