java.io.NotSerializableException: java.util.ArrayList$SubList異常解決辦法


5/17/2017 7:15:51 PM


  1. 問題是什么嗤锉?(What)
    • 未序列化異常
    • 由ArrayList的subList方法引起的
    • SubList類未實現(xiàn)序列化接口Serializable
  2. 為什么會出現(xiàn)這種現(xiàn)象瘟忱?(Why)
    • 查API
      • 返回的是List的一個視圖非實體對象
    List<E> subList(int fromIndex, int toIndex)
    Returns: a view of the specified range within this list
    Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the returned list is empty.) The returned list is backed(支持) by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa. The returned list supports all of the optional list operations supported by this list.
    • 序列化需要使用的是實體對象故序列化時出現(xiàn)異常
  3. 如何解決苫幢?(How)
    • new一個對象出來存儲子列表數(shù)據(jù)
    List tmpList = new ArrayList<>(sourceList.subList(fromIndex, endIndex));
    
  4. 修復(fù)(Result)
    • 根據(jù)錯誤日志定位缺陷代碼位置-->修復(fù)
    • 驗證功能
  5. 源碼
    • SubList是ArrayList的內(nèi)部類
    • 此對象并未存儲數(shù)據(jù)韩肝,只是可以操作原數(shù)據(jù)
     public List<E> subList(int fromIndex, int toIndex) {
            subListRangeCheck(fromIndex, toIndex, size);
            return new SubList(this, 0, fromIndex, toIndex);
        }
    
     private class SubList extends AbstractList<E> implements RandomAccess {
            private final AbstractList<E> parent;
            private final int parentOffset;
            private final int offset;
            int size;
    
            SubList(AbstractList<E> parent,
                    int offset, int fromIndex, int toIndex) {
                this.parent = parent;
                this.parentOffset = fromIndex;
                this.offset = offset + fromIndex;
                this.size = toIndex - fromIndex;
                this.modCount = ArrayList.this.modCount;
            }
    
            public E set(int index, E e) {
                rangeCheck(index);
                checkForComodification();
                E oldValue = ArrayList.this.elementData(offset + index);
                ArrayList.this.elementData[offset + index] = e;
                return oldValue;
            }
    
            public E get(int index) {
                rangeCheck(index);
                checkForComodification();
                return ArrayList.this.elementData(offset + index);
            }
    
            public int size() {
                checkForComodification();
                return this.size;
            }
    
            public void add(int index, E e) {
                rangeCheckForAdd(index);
                checkForComodification();
                parent.add(parentOffset + index, e);
                this.modCount = parent.modCount;
                this.size++;
            }
    
            public E remove(int index) {
                rangeCheck(index);
                checkForComodification();
                E result = parent.remove(parentOffset + index);
                this.modCount = parent.modCount;
                this.size--;
                return result;
            }
    
            protected void removeRange(int fromIndex, int toIndex) {
                checkForComodification();
                parent.removeRange(parentOffset + fromIndex,
                                   parentOffset + toIndex);
                this.modCount = parent.modCount;
                this.size -= toIndex - fromIndex;
            }
    
            public boolean addAll(Collection<? extends E> c) {
                return addAll(this.size, c);
            }
    
            public boolean addAll(int index, Collection<? extends E> c) {
                rangeCheckForAdd(index);
                int cSize = c.size();
                if (cSize==0)
                    return false;
    
                checkForComodification();
                parent.addAll(parentOffset + index, c);
                this.modCount = parent.modCount;
                this.size += cSize;
                return true;
            }
    
            public Iterator<E> iterator() {
                return listIterator();
            }
    
            public ListIterator<E> listIterator(final int index) {
                checkForComodification();
                rangeCheckForAdd(index);
                final int offset = this.offset;
    
                return new ListIterator<E>() {
                    int cursor = index;
                    int lastRet = -1;
                    int expectedModCount = ArrayList.this.modCount;
    
                    public boolean hasNext() {
                        return cursor != SubList.this.size;
                    }
    
                    @SuppressWarnings("unchecked")
                    public E next() {
                        checkForComodification();
                        int i = cursor;
                        if (i >= SubList.this.size)
                            throw new NoSuchElementException();
                        Object[] elementData = ArrayList.this.elementData;
                        if (offset + i >= elementData.length)
                            throw new ConcurrentModificationException();
                        cursor = i + 1;
                        return (E) elementData[offset + (lastRet = i)];
                    }
    
                    public boolean hasPrevious() {
                        return cursor != 0;
                    }
    
                    @SuppressWarnings("unchecked")
                    public E previous() {
                        checkForComodification();
                        int i = cursor - 1;
                        if (i < 0)
                            throw new NoSuchElementException();
                        Object[] elementData = ArrayList.this.elementData;
                        if (offset + i >= elementData.length)
                            throw new ConcurrentModificationException();
                        cursor = i;
                        return (E) elementData[offset + (lastRet = i)];
                    }
    
                    public int nextIndex() {
                        return cursor;
                    }
    
                    public int previousIndex() {
                        return cursor - 1;
                    }
    
                    public void remove() {
                        if (lastRet < 0)
                            throw new IllegalStateException();
                        checkForComodification();
    
                        try {
                            SubList.this.remove(lastRet);
                            cursor = lastRet;
                            lastRet = -1;
                            expectedModCount = ArrayList.this.modCount;
                        } catch (IndexOutOfBoundsException ex) {
                            throw new ConcurrentModificationException();
                        }
                    }
    
                    public void set(E e) {
                        if (lastRet < 0)
                            throw new IllegalStateException();
                        checkForComodification();
    
                        try {
                            ArrayList.this.set(offset + lastRet, e);
                        } catch (IndexOutOfBoundsException ex) {
                            throw new ConcurrentModificationException();
                        }
                    }
    
                    public void add(E e) {
                        checkForComodification();
    
                        try {
                            int i = cursor;
                            SubList.this.add(i, e);
                            cursor = i + 1;
                            lastRet = -1;
                            expectedModCount = ArrayList.this.modCount;
                        } catch (IndexOutOfBoundsException ex) {
                            throw new ConcurrentModificationException();
                        }
                    }
    
                    final void checkForComodification() {
                        if (expectedModCount != ArrayList.this.modCount)
                            throw new ConcurrentModificationException();
                    }
                };
            }
    

PS:

  • ArrayList重寫了readObject和writeObject所以序列化和反序列化時使用這兩個方法
  • 這也是為什么private transient Object[] elementData;也可以序列化數(shù)據(jù)(transient語義是序列化時不序列化此屬性)漾峡,由于覆寫了讀寫對象的方法,則序列化(反序列化)時使用此讀寫對象方式
 /**
 * The array buffer into which the elements of the ArrayList are stored.
 * The capacity of the ArrayList is the length of this array buffer.
 */
 private transient Object[] elementData;
 /**
 * The size of the ArrayList (the number of elements it contains).
 *
 * @serial
 */
 private int size;
 
 /**
 * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
 * deserialize it).
 */
 private void readObject(java.io.ObjectInputStream s)
 throws java.io.IOException, ClassNotFoundException {
 // Read in size, and any hidden stuff
 s.defaultReadObject();
 
 // Read in array length and allocate array
 int arrayLength = s.readInt();
 Object[] a = elementData = new Object[arrayLength];
 
 // Read in all elements in the proper order.
 for (int i=0; i<size; i++)
 a[i] = s.readObject();
 }
 
 private void writeObject(java.io.ObjectOutputStream s)
 throws java.io.IOException{
 // Write out element count, and any hidden stuff
 int expectedModCount = modCount;
 s.defaultWriteObject();
 
 // Write out array length
 s.writeInt(elementData.length);
 
 // Write out all elements in the proper order.
 for (int i=0; i<size; i++)
 s.writeObject(elementData[i]);
 
 if (modCount != expectedModCount) {
 throw new ConcurrentModificationException();
 }
 
 }
 ```
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市烙无,隨后出現(xiàn)的幾起案子遍尺,更是在濱河造成了極大的恐慌,老刑警劉巖迂苛,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件三幻,死亡現(xiàn)場離奇詭異呐能,居然都是意外死亡,警方通過查閱死者的電腦和手機朗徊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門偎漫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來象踊,“玉大人,你說我怎么就攤上這事通危【盏” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵头镊,是天一觀的道長。 經(jīng)常有香客問我相艇,道長,這世上最難降的妖魔是什么留储? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任获讳,我火速辦了婚禮活喊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘帅矗。我一直安慰自己煞烫,他們只是感情好,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布尤勋。 她就那樣靜靜地躺著茵宪,像睡著了一般稀火。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赌朋,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天凰狞,我揣著相機與錄音,去河邊找鬼沛慢。 笑死赡若,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的团甲。 我是一名探鬼主播逾冬,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了身腻?” 一聲冷哼從身側(cè)響起产还,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤嘀趟,失蹤者是張志新(化名)和其女友劉穎脐区,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體她按,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡牛隅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了酌泰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片倔叼。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖宫莱,靈堂內(nèi)的尸體忽然破棺而出丈攒,到底是詐尸還是另有隱情,我是刑警寧澤授霸,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布巡验,位于F島的核電站,受9級特大地震影響碘耳,放射性物質(zhì)發(fā)生泄漏显设。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一辛辨、第九天 我趴在偏房一處隱蔽的房頂上張望捕捂。 院中可真熱鬧,春花似錦斗搞、人聲如沸指攒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽允悦。三九已至,卻和暖如春虑啤,著一層夾襖步出監(jiān)牢的瞬間隙弛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工狞山, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留全闷,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓萍启,卻偏偏與公主長得像总珠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容