代碼席爾瓦 2021-09-18 06:09:52 阅读数:178
IllegalArgumentException, InvocationTargetException
{
…
//如果當前的類型為枚舉類型,那麼調用當前方法直接拋异常
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException(“Cannot reflectively create enum objects”);
…
return inst;
}
而ordinal則是代錶每個枚舉常量對應的申明順序,說明枚舉的排序方式默認按照申明的順序進行排序,那麼序列化和反序列化的過程是什麼樣的呢?我們來編寫一個序列化的代碼,debug跟代碼以後,可以看到最終是調用了java.lang.Enum#valueOf
方法來實現的反序列化的。而序列化後的內容大概如下:
大概可以看到,序列化的內容主要包含枚舉類型和枚舉的每個名稱,接著我們看看java.lang.Enum#valueOf
方法的源碼:
從源碼和注釋中我們都可以看出來,如果此時A服務使用的枚舉類為舊版本,只有五個常量,而B服務的枚舉中包含了新的常量,這個時候在反序列化的時候,由於name == null,則會直接拋出异常,從這我們也終於看出來,為什麼規範中會强制不允許使用枚舉類型作為參數進行序列化傳遞了
在翻閱各大規範手册的時候,我看到阿裏手册中有這麼一條:
吸引了我,因為在以前開發過程中,我就遇到了一個可變參數埋下的坑,接下來我們就來看看可變參數相關的一個坑。
相信很多人都編寫過企業裏使用的工具類,而我當初在編寫一個Boolean類型的工具類的時候,編寫了大概如下的兩個方法:
這兩個方法看起來就是一樣的,都是為了傳遞多個布爾類型的參數進來,判斷多個條件連接在一起,是否能成為true的結果,但是當我編寫測試的代碼的時候,問題出現了:
這樣的方法會返回什麼呢?其實當代碼剛剛編寫完畢的時候,就會發現編譯器已經報錯了,會提示:
模糊的函數匹配,因為編譯器認為有兩個方法都完全滿足當前的函數,那麼為什麼會這樣的呢?我們知道在Java1.5以後加入了自動拆箱裝箱的過程,為了兼容1.5以前的jdk版本,將此過程設置為了三個階段:
而我們使用的測試方法中,在第一階段,判斷jdk版本,是不是不允許自動裝箱拆箱,明顯jdk版本大於1.5,允許自動拆箱裝箱,因此進入第二階段,此時判斷是否存在更符合的參數方法,比如我們傳遞了三個布爾類型的參數,但是如果此時有三個布爾參數的方法,則會優先匹配此方法,而不是匹配可變參數的方法,很明顯也沒有,此時就會進入第三階段,完成裝箱拆箱以後,再去查找匹配的變長參數的方法,這個時候由於完成了拆箱裝箱,兩個類型會視為一個類型,發現方法上有兩個匹配的方法,這時候就會報錯了。
那麼我們有木有辦法處理這個問題呢?畢竟我們熟悉的org.apache.commons.lang3.BooleanUtils
工具類中也有類似的方法,我們都明白,變長參數其實就是會將當前的多個傳遞的參數裝入數組後,再去處理,那麼可以在傳遞的過程中,將所有的參數通過數組包裹,這個時候就不會發生拆箱裝箱過程了!例如:
而參考其他框架源碼大神的寫法中,也有針對這個的編寫的範例:
通過此種方法可以保證如果傳入的是基本類型,直接匹配當前方法,如果是包裝類型,則在第二階段以後匹配到當前函數,最終都是調用了BooleanUtils中基本類型的and方法
List作為我們企業開發中最常見的一個集合類,在開發過程中更是經常遇到去重,轉換等操作,但是集合類操作的不好很多時候會導致我們的程序性能緩慢或者出現异常的風險,例如阿裏手册中提到過:
而手册中的這些xxList方法則是我們開發過程中比較常用的,那麼為什麼阿裏手册會有這些規範呢?我們來看看第一個方法subList
,首先我們先看看SubList類和ArrayList類的區別,從類圖上我們可以看出來兩個類之間並沒有繼承關系:
所以手册上不允許使用subList
强轉為ArrayList,那麼為什麼原集合不能進行增删改查操作呢?我們來看看其源碼:
我們可以看到代碼的邏輯只有兩步,第一步檢查當前的索引和長度是否變化,第二步構建新的SubList出來並且返回。從注釋我們也可以了解到,SubList中包含的範圍,如果對其進行增删改查操作,都會導致原來的集合發生變化,並且是從當前的index + offSet進行變化。那麼為什麼我們這個時候對原來的ArrayList進行增删改查操作的時候會導致SubList集合操作异常呢?我們來看看ArrayList的add方法:
我們可以看到一點,每次元素新增的時候都會有一個 ensureCapacityInternal(size + 1);
操作,這個操作會導致modCount長度變化,而modCount則是在SubList的構造中用來記錄長度使用的:
而SubList的get操作的源碼如下:
可以看到每次都會去校驗一下下標和modCount,我們來看看checkForComodification
方法:
可見每次都會檢查,如果發現原來集合的長度變化了,就會拋出异常,那麼使用SubList的時候為什麼要注意原集合是否被更改的原因就在這裏了。
我將這三次阿裏面試的題目全部分專題整理出來,並附帶上詳細的答案解析,生成了一份PDF文檔
CodeChina開源項目:【一線大廠Java面試題解析+核心總結學習筆記+最新講解視頻】
還有更多的Redis、MySQL、JVM、Kafka、微服務、Spring全家桶等學習筆記這裏就不一一列舉出來
版权声明:本文为[代碼席爾瓦]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/09/20210918060951430x.html