無(wú)標(biāo)題文章

```

/*

* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*

*/

/*

* Written by Doug Lea with assistance from members of JCP JSR-166

* Expert Group.? Adapted and released, under explicit permission,

* from JDK ArrayList.java which carries the following copyright:

*

* Copyright 1997 by Sun Microsystems, Inc.,

* 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.

* All rights reserved.

*/

packagejava.util.concurrent;

importjava.util.AbstractList;

importjava.util.Arrays;

importjava.util.Collection;

importjava.util.Comparator;

importjava.util.ConcurrentModificationException;

importjava.util.Iterator;

importjava.util.List;

importjava.util.ListIterator;

importjava.util.NoSuchElementException;

importjava.util.Objects;

importjava.util.RandomAccess;

importjava.util.Spliterator;

importjava.util.Spliterators;

importjava.util.concurrent.locks.ReentrantLock;

importjava.util.function.Consumer;

importjava.util.function.Predicate;

importjava.util.function.UnaryOperator;

/**

* A thread-safe variant of {@linkjava.util.ArrayList} in which all mutative

* operations ({@codeadd}, {@codeset}, and so on) are implemented by

* making a fresh copy of the underlying array.

*

*

This is ordinarily too costly, but may bemoreefficient

* than alternatives when traversal operations vastly outnumber

* mutations, and is useful when you cannot or don't want to

* synchronize traversals, yet need to preclude interference among

* concurrent threads.? The "snapshot" style iterator method uses a

* reference to the state of the array at the point that the iterator

* was created. This array never changes during the lifetime of the

* iterator, so interference is impossible and the iterator is

* guaranteed not to throw {@codeConcurrentModificationException}.

* The iterator will not reflect additions, removals, or changes to

* the list since the iterator was created.? Element-changing

* operations on iterators themselves ({@coderemove}, {@codeset}, and

* {@codeadd}) are not supported. These methods throw

* {@codeUnsupportedOperationException}.

*

*

All elements are permitted, including {@codenull}.

*

*

Memory consistency effects: As with other concurrent

* collections, actions in a thread prior to placing an object into a

* {@codeCopyOnWriteArrayList}

*happen-before

* actions subsequent to the access or removal of that element from

* the {@codeCopyOnWriteArrayList} in another thread.

*

*

This class is a member of the

*

* Java Collections Framework.

*

*@since1.5

*@authorDoug Lea

*@paramthe type of elements held in this collection

*/

public classCopyOnWriteArrayList

implementsList,RandomAccess,Cloneable,java.io.Serializable {

private static final longserialVersionUID=8673264195747942595L;

/** The lock protecting all mutators */

final transientReentrantLocklock=newReentrantLock();

/** The array, accessed only via getArray/setArray. */

private transient volatileObject[]array;

/**

* Gets the array.? Non-private so as to also be accessible

* from CopyOnWriteArraySet class.

*/

finalObject[]getArray() {

returnarray;

}

/**

* Sets the array.

*/

final voidsetArray(Object[] a) {

array= a;

}

/**

* Creates an empty list.

*/

publicCopyOnWriteArrayList() {

setArray(newObject[0]);

}

/**

* Creates a list containing the elements of the specified

* collection, in the order they are returned by the collection's

* iterator.

*

*@paramcthe collection of initially held elements

*@throwsNullPointerException if the specified collection is null

*/

publicCopyOnWriteArrayList(Collection c) {

Object[] elements;

if(c.getClass() == CopyOnWriteArrayList.class)

elements = ((CopyOnWriteArrayList)c).getArray();

else{

elements = c.toArray();

// c.toArray might (incorrectly) not return Object[] (see 6260652)

if(elements.getClass() != Object[].class)

elements = Arrays.copyOf(elements,elements.length,Object[].class);

}

setArray(elements);

}

/**

* Creates a list holding a copy of the given array.

*

*@paramtoCopyInthe array (a copy of this array is used as the

*? ? ? ? internal array)

*@throwsNullPointerException if the specified array is null

*/

publicCopyOnWriteArrayList(E[] toCopyIn) {

setArray(Arrays.copyOf(toCopyIn,toCopyIn.length,Object[].class));

}

/**

* Returns the number of elements in this list.

*

*@returnthe number of elements in this list

*/

public intsize() {

returngetArray().length;

}

/**

* Returns {@codetrue} if this list contains no elements.

*

*@return{@codetrue} if this list contains no elements

*/

public booleanisEmpty() {

returnsize() ==0;

}

/**

* Tests for equality, coping with nulls.

*/

private static booleaneq(Object o1,Object o2) {

return(o1 ==null) ? o2 ==null: o1.equals(o2);

}

/**

* static version of indexOf, to allow repeated calls without

* needing to re-acquire array each time.

*@paramoelement to search for

*@paramelementsthe array

*@paramindexfirst index to search

*@paramfenceone past last index to search

*@returnindex of element, or -1 if absent

*/

private static intindexOf(Object o,Object[] elements,

intindex, intfence) {

if(o ==null) {

for(inti = index;i < fence;i++)

if(elements[i] ==null)

returni;

}else{

for(inti = index;i < fence;i++)

if(o.equals(elements[i]))

returni;

}

return-1;

}

/**

* static version of lastIndexOf.

*@paramoelement to search for

*@paramelementsthe array

*@paramindexfirst index to search

*@returnindex of element, or -1 if absent

*/

private static intlastIndexOf(Object o,Object[] elements, intindex) {

if(o ==null) {

for(inti = index;i >=0;i--)

if(elements[i] ==null)

returni;

}else{

for(inti = index;i >=0;i--)

if(o.equals(elements[i]))

returni;

}

return-1;

}

/**

* Returns {@codetrue} if this list contains the specified element.

* More formally, returns {@codetrue} if and only if this list contains

* at least one element {@codee} such that

*(o==null ? e==null : o.equals(e)).

*

*@paramoelement whose presence in this list is to be tested

*@return{@codetrue} if this list contains the specified element

*/

public booleancontains(Object o) {

Object[] elements = getArray();

returnindexOf(o,elements,0,elements.length) >=0;

}

/**

* {@inheritDoc}

*/

public intindexOf(Object o) {

Object[] elements = getArray();

returnindexOf(o,elements,0,elements.length);

}

/**

* Returns the index of the first occurrence of the specified element in

* this list, searching forwards from {@codeindex}, or returns -1 if

* the element is not found.

* More formally, returns the lowest index {@codei} such that

*(i >= index && (e==null ? get(i)==null : e.equals(get(i)))),

* or -1 if there is no such index.

*

*@parameelement to search for

*@paramindexindex to start searching from

*@returnthe index of the first occurrence of the element in

*? ? ? ? this list at position {@codeindex} or later in the list;

*? ? ? ? {@code-1} if the element is not found.

*@throwsIndexOutOfBoundsException if the specified index is negative

*/

public intindexOf(Ee, intindex) {

Object[] elements = getArray();

returnindexOf(e,elements,index,elements.length);

}

/**

* {@inheritDoc}

*/

public intlastIndexOf(Object o) {

Object[] elements = getArray();

returnlastIndexOf(o,elements,elements.length-1);

}

/**

* Returns the index of the last occurrence of the specified element in

* this list, searching backwards from {@codeindex}, or returns -1 if

* the element is not found.

* More formally, returns the highest index {@codei} such that

*(i <= index && (e==null ? get(i)==null : e.equals(get(i)))),

* or -1 if there is no such index.

*

*@parameelement to search for

*@paramindexindex to start searching backwards from

*@returnthe index of the last occurrence of the element at position

*? ? ? ? less than or equal to {@codeindex} in this list;

*? ? ? ? -1 if the element is not found.

*@throwsIndexOutOfBoundsException if the specified index is greater

*? ? ? ? than or equal to the current size of this list

*/

public intlastIndexOf(Ee, intindex) {

Object[] elements = getArray();

returnlastIndexOf(e,elements,index);

}

/**

* Returns a shallow copy of this list.? (The elements themselves

* are not copied.)

*

*@returna clone of this list

*/

publicObjectclone() {

try{

@SuppressWarnings("unchecked")

CopyOnWriteArrayList clone =

(CopyOnWriteArrayList)super.clone();

clone.resetLock();

returnclone;

}catch(CloneNotSupportedException e) {

// this shouldn't happen, since we are Cloneable

throw newInternalError();

}

}

/**

* Returns an array containing all of the elements in this list

* in proper sequence (from first to last element).

*

*

The returned array will be "safe" in that no references to it are

* maintained by this list.? (In other words, this method must allocate

* a new array).? The caller is thus free to modify the returned array.

*

*

This method acts as bridge between array-based and collection-based

* APIs.

*

*@returnan array containing all the elements in this list

*/

publicObject[]toArray() {

Object[] elements = getArray();

returnArrays.copyOf(elements,elements.length);

}

/**

* Returns an array containing all of the elements in this list in

* proper sequence (from first to last element); the runtime type of

* the returned array is that of the specified array.? If the list fits

* in the specified array, it is returned therein.? Otherwise, a new

* array is allocated with the runtime type of the specified array and

* the size of this list.

*

*

If this list fits in the specified array with room to spare

* (i.e., the array has more elements than this list), the element in

* the array immediately following the end of the list is set to

* {@codenull}.? (This is useful in determining the length of this

* listonlyif the caller knows that this list does not contain

* any null elements.)

*

*

Like the {@link#toArray()} method, this method acts as bridge between

* array-based and collection-based APIs.? Further, this method allows

* precise control over the runtime type of the output array, and may,

* under certain circumstances, be used to save allocation costs.

*

*

Suppose {@codex} is a list known to contain only strings.

* The following code can be used to dump the list into a newly

* allocated array of {@codeString}:

*

*

{@codeString[] y = x.toArray(new String[0]);}

*

* Note that {@codetoArray(new Object[0])} is identical in function to

* {@codetoArray()}.

*

*@paramathe array into which the elements of the list are to

*? ? ? ? ? be stored, if it is big enough; otherwise, a new array of the

*? ? ? ? ? same runtime type is allocated for this purpose.

*@returnan array containing all the elements in this list

*@throwsArrayStoreException if the runtime type of the specified array

*? ? ? ? is not a supertype of the runtime type of every element in

*? ? ? ? this list

*@throwsNullPointerException if the specified array is null

*/

@SuppressWarnings("unchecked")

publicT[]toArray(Ta[]) {

Object[] elements = getArray();

intlen = elements.length;

if(a.length< len)

return(T[]) Arrays.copyOf(elements,len,a.getClass());

else{

System.arraycopy(elements,0,a,0,len);

if(a.length> len)

a[len] =null;

returna;

}

}

// Positional Access Operations

@SuppressWarnings("unchecked")

privateEget(Object[] a, intindex) {

return(E) a[index];

}

/**

* {@inheritDoc}

*

*@throwsIndexOutOfBoundsException {@inheritDoc}

*/

publicEget(intindex) {

returnget(getArray(),index);

}

/**

* Replaces the element at the specified position in this list with the

* specified element.

*

*@throwsIndexOutOfBoundsException {@inheritDoc}

*/

publicEset(intindex,Eelement) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

EoldValue = get(elements,index);

if(oldValue != element) {

intlen = elements.length;

Object[] newElements = Arrays.copyOf(elements,len);

newElements[index] = element;

setArray(newElements);

}else{

// Not quite a no-op; ensures volatile write semantics

setArray(elements);

}

returnoldValue;

}finally{

lock.unlock();

}

}

/**

* Appends the specified element to the end of this list.

*

*@parameelement to be appended to this list

*@return{@codetrue} (as specified by {@linkCollection#add})

*/

public booleanadd(Ee) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

Object[] newElements = Arrays.copyOf(elements,len +1);

newElements[len] = e;

setArray(newElements);

return true;

}finally{

lock.unlock();

}

}

/**

* Inserts the specified element at the specified position in this

* list. Shifts the element currently at that position (if any) and

* any subsequent elements to the right (adds one to their indices).

*

*@throwsIndexOutOfBoundsException {@inheritDoc}

*/

public voidadd(intindex,Eelement) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

if(index > len || index <0)

throw newIndexOutOfBoundsException("Index: "+index+

", Size: "+len);

Object[] newElements;

intnumMoved = len - index;

if(numMoved ==0)

newElements = Arrays.copyOf(elements,len +1);

else{

newElements =newObject[len +1];

System.arraycopy(elements,0,newElements,0,index);

System.arraycopy(elements,index,newElements,index +1,

numMoved);

}

newElements[index] = element;

setArray(newElements);

}finally{

lock.unlock();

}

}

/**

* Removes the element at the specified position in this list.

* Shifts any subsequent elements to the left (subtracts one from their

* indices).? Returns the element that was removed from the list.

*

*@throwsIndexOutOfBoundsException {@inheritDoc}

*/

publicEremove(intindex) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

EoldValue = get(elements,index);

intnumMoved = len - index -1;

if(numMoved ==0)

setArray(Arrays.copyOf(elements,len -1));

else{

Object[] newElements =newObject[len -1];

System.arraycopy(elements,0,newElements,0,index);

System.arraycopy(elements,index +1,newElements,index,

numMoved);

setArray(newElements);

}

returnoldValue;

}finally{

lock.unlock();

}

}

/**

* Removes the first occurrence of the specified element from this list,

* if it is present.? If this list does not contain the element, it is

* unchanged.? More formally, removes the element with the lowest index

* {@codei} such that

*(o==null ? get(i)==null : o.equals(get(i)))

* (if such an element exists).? Returns {@codetrue} if this list

* contained the specified element (or equivalently, if this list

* changed as a result of the call).

*

*@paramoelement to be removed from this list, if present

*@return{@codetrue} if this list contained the specified element

*/

public booleanremove(Object o) {

Object[] snapshot = getArray();

intindex =indexOf(o,snapshot,0,snapshot.length);

return(index <0) ?false: remove(o,snapshot,index);

}

/**

* A version of remove(Object) using the strong hint that given

* recent snapshot contains o at the given index.

*/

private booleanremove(Object o,Object[] snapshot, intindex) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] current = getArray();

intlen = current.length;

if(snapshot != current) findIndex: {

intprefix = Math.min(index,len);

for(inti =0;i < prefix;i++) {

if(current[i] != snapshot[i] &&eq(o,current[i])) {

index = i;

breakfindIndex;

}

}

if(index >= len)

return false;

if(current[index] == o)

breakfindIndex;

index =indexOf(o,current,index,len);

if(index <0)

return false;

}

Object[] newElements =newObject[len -1];

System.arraycopy(current,0,newElements,0,index);

System.arraycopy(current,index +1,

newElements,index,

len - index -1);

setArray(newElements);

return true;

}finally{

lock.unlock();

}

}

/**

* Removes from this list all of the elements whose index is between

* {@codefromIndex}, inclusive, and {@codetoIndex}, exclusive.

* Shifts any succeeding elements to the left (reduces their index).

* This call shortens the list by {@code(toIndex - fromIndex)} elements.

* (If {@codetoIndex==fromIndex}, this operation has no effect.)

*

*@paramfromIndexindex of first element to be removed

*@paramtoIndexindex after last element to be removed

*@throwsIndexOutOfBoundsException if fromIndex or toIndex out of range

*? ? ? ? ({@codefromIndex < 0 || toIndex > size() || toIndex < fromIndex})

*/

voidremoveRange(intfromIndex, inttoIndex) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

if(fromIndex <0|| toIndex > len || toIndex < fromIndex)

throw newIndexOutOfBoundsException();

intnewlen = len - (toIndex - fromIndex);

intnumMoved = len - toIndex;

if(numMoved ==0)

setArray(Arrays.copyOf(elements,newlen));

else{

Object[] newElements =newObject[newlen];

System.arraycopy(elements,0,newElements,0,fromIndex);

System.arraycopy(elements,toIndex,newElements,

fromIndex,numMoved);

setArray(newElements);

}

}finally{

lock.unlock();

}

}

/**

* Appends the element, if not present.

*

*@parameelement to be added to this list, if absent

*@return{@codetrue} if the element was added

*/

public booleanaddIfAbsent(Ee) {

Object[] snapshot = getArray();

returnindexOf(e,snapshot,0,snapshot.length) >=0?false:

addIfAbsent(e,snapshot);

}

/**

* A version of addIfAbsent using the strong hint that given

* recent snapshot does not contain e.

*/

private booleanaddIfAbsent(Ee,Object[] snapshot) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] current = getArray();

intlen = current.length;

if(snapshot != current) {

// Optimize for lost race to another addXXX operation

intcommon = Math.min(snapshot.length,len);

for(inti =0;i < common;i++)

if(current[i] != snapshot[i] &&eq(e,current[i]))

return false;

if(indexOf(e,current,common,len) >=0)

return false;

}

Object[] newElements = Arrays.copyOf(current,len +1);

newElements[len] = e;

setArray(newElements);

return true;

}finally{

lock.unlock();

}

}

/**

* Returns {@codetrue} if this list contains all of the elements of the

* specified collection.

*

*@paramccollection to be checked for containment in this list

*@return{@codetrue} if this list contains all of the elements of the

*? ? ? ? specified collection

*@throwsNullPointerException if the specified collection is null

*@see#contains(Object)

*/

public booleancontainsAll(Collection c) {

Object[] elements = getArray();

intlen = elements.length;

for(Object e : c) {

if(indexOf(e,elements,0,len) <0)

return false;

}

return true;

}

/**

* Removes from this list all of its elements that are contained in

* the specified collection. This is a particularly expensive operation

* in this class because of the need for an internal temporary array.

*

*@paramccollection containing elements to be removed from this list

*@return{@codetrue} if this list changed as a result of the call

*@throwsClassCastException if the class of an element of this list

*? ? ? ? is incompatible with the specified collection

*? ? ? ? (optional)

*@throwsNullPointerException if this list contains a null element and the

*? ? ? ? specified collection does not permit null elements

*? ? ? ? (optional),

*? ? ? ? or if the specified collection is null

*@see#remove(Object)

*/

public booleanremoveAll(Collection c) {

if(c ==null)throw newNullPointerException();

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

if(len !=0) {

// temp array holds those elements we know we want to keep

intnewlen =0;

Object[] temp =newObject[len];

for(inti =0;i < len;++i) {

Object element = elements[i];

if(!c.contains(element))

temp[newlen++] = element;

}

if(newlen != len) {

setArray(Arrays.copyOf(temp,newlen));

return true;

}

}

return false;

}finally{

lock.unlock();

}

}

/**

* Retains only the elements in this list that are contained in the

* specified collection.? In other words, removes from this list all of

* its elements that are not contained in the specified collection.

*

*@paramccollection containing elements to be retained in this list

*@return{@codetrue} if this list changed as a result of the call

*@throwsClassCastException if the class of an element of this list

*? ? ? ? is incompatible with the specified collection

*? ? ? ? (optional)

*@throwsNullPointerException if this list contains a null element and the

*? ? ? ? specified collection does not permit null elements

*? ? ? ? (optional),

*? ? ? ? or if the specified collection is null

*@see#remove(Object)

*/

public booleanretainAll(Collection c) {

if(c ==null)throw newNullPointerException();

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

if(len !=0) {

// temp array holds those elements we know we want to keep

intnewlen =0;

Object[] temp =newObject[len];

for(inti =0;i < len;++i) {

Object element = elements[i];

if(c.contains(element))

temp[newlen++] = element;

}

if(newlen != len) {

setArray(Arrays.copyOf(temp,newlen));

return true;

}

}

return false;

}finally{

lock.unlock();

}

}

/**

* Appends all of the elements in the specified collection that

* are not already contained in this list, to the end of

* this list, in the order that they are returned by the

* specified collection's iterator.

*

*@paramccollection containing elements to be added to this list

*@returnthe number of elements added

*@throwsNullPointerException if the specified collection is null

*@see#addIfAbsent(Object)

*/

public intaddAllAbsent(Collection c) {

Object[] cs = c.toArray();

if(cs.length==0)

return0;

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

intadded =0;

// uniquify and compact elements in cs

for(inti =0;i < cs.length;++i) {

Object e = cs[i];

if(indexOf(e,elements,0,len) <0&&

indexOf(e,cs,0,added) <0)

cs[added++] = e;

}

if(added >0) {

Object[] newElements = Arrays.copyOf(elements,len + added);

System.arraycopy(cs,0,newElements,len,added);

setArray(newElements);

}

returnadded;

}finally{

lock.unlock();

}

}

/**

* Removes all of the elements from this list.

* The list will be empty after this call returns.

*/

public voidclear() {

finalReentrantLock lock =this.lock;

lock.lock();

try{

setArray(newObject[0]);

}finally{

lock.unlock();

}

}

/**

* Appends all of the elements in the specified collection to the end

* of this list, in the order that they are returned by the specified

* collection's iterator.

*

*@paramccollection containing elements to be added to this list

*@return{@codetrue} if this list changed as a result of the call

*@throwsNullPointerException if the specified collection is null

*@see#add(Object)

*/

public booleanaddAll(Collection c) {

Object[] cs = (c.getClass() == CopyOnWriteArrayList.class) ?

((CopyOnWriteArrayList)c).getArray() : c.toArray();

if(cs.length==0)

return false;

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

if(len ==0&& cs.getClass() == Object[].class)

setArray(cs);

else{

Object[] newElements = Arrays.copyOf(elements,len + cs.length);

System.arraycopy(cs,0,newElements,len,cs.length);

setArray(newElements);

}

return true;

}finally{

lock.unlock();

}

}

/**

* Inserts all of the elements in the specified collection into this

* list, starting at the specified position.? Shifts the element

* currently at that position (if any) and any subsequent elements to

* the right (increases their indices).? The new elements will appear

* in this list in the order that they are returned by the

* specified collection's iterator.

*

*@paramindexindex at which to insert the first element

*? ? ? ? from the specified collection

*@paramccollection containing elements to be added to this list

*@return{@codetrue} if this list changed as a result of the call

*@throwsIndexOutOfBoundsException {@inheritDoc}

*@throwsNullPointerException if the specified collection is null

*@see#add(int,Object)

*/

public booleanaddAll(intindex,Collection c) {

Object[] cs = c.toArray();

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

if(index > len || index <0)

throw newIndexOutOfBoundsException("Index: "+index+

", Size: "+len);

if(cs.length==0)

return false;

intnumMoved = len - index;

Object[] newElements;

if(numMoved ==0)

newElements = Arrays.copyOf(elements,len + cs.length);

else{

newElements =newObject[len + cs.length];

System.arraycopy(elements,0,newElements,0,index);

System.arraycopy(elements,index,

newElements,index + cs.length,

numMoved);

}

System.arraycopy(cs,0,newElements,index,cs.length);

setArray(newElements);

return true;

}finally{

lock.unlock();

}

}

public voidforEach(Consumer action) {

if(action ==null)throw newNullPointerException();

Object[] elements = getArray();

intlen = elements.length;

for(inti =0;i < len;++i) {

@SuppressWarnings("unchecked")Ee = (E) elements[i];

action.accept(e);

}

}

public booleanremoveIf(Predicate filter) {

if(filter ==null)throw newNullPointerException();

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

if(len !=0) {

intnewlen =0;

Object[] temp =newObject[len];

for(inti =0;i < len;++i) {

@SuppressWarnings("unchecked")Ee = (E) elements[i];

if(!filter.test(e))

temp[newlen++] = e;

}

if(newlen != len) {

setArray(Arrays.copyOf(temp,newlen));

return true;

}

}

return false;

}finally{

lock.unlock();

}

}

public voidreplaceAll(UnaryOperator operator) {

if(operator ==null)throw newNullPointerException();

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

Object[] newElements = Arrays.copyOf(elements,len);

for(inti =0;i < len;++i) {

@SuppressWarnings("unchecked")Ee = (E) elements[i];

newElements[i] = operator.apply(e);

}

setArray(newElements);

}finally{

lock.unlock();

}

}

public voidsort(Comparator c) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

Object[] newElements = Arrays.copyOf(elements,elements.length);

@SuppressWarnings("unchecked")E[] es = (E[])newElements;

Arrays.sort(es,c);

setArray(newElements);

}finally{

lock.unlock();

}

}

/**

* Saves this list to a stream (that is, serializes it).

*

*@paramsthe stream

*@throwsjava.io.IOException if an I/O error occurs

*@serialDataThe length of the array backing the list is emitted

*? ? ? ? ? ? ? (int), followed by all of its elements (each an Object)

*? ? ? ? ? ? ? in the proper order.

*/

private voidwriteObject(java.io.ObjectOutputStream s)

throwsjava.io.IOException {

s.defaultWriteObject();

Object[] elements = getArray();

// Write out array length

s.writeInt(elements.length);

// Write out all elements in the proper order.

for(Object element : elements)

s.writeObject(element);

}

/**

* Reconstitutes this list from a stream (that is, deserializes it).

*@paramsthe stream

*@throwsClassNotFoundException if the class of a serialized object

*? ? ? ? could not be found

*@throwsjava.io.IOException if an I/O error occurs

*/

private voidreadObject(java.io.ObjectInputStream s)

throwsjava.io.IOException,ClassNotFoundException {

s.defaultReadObject();

// bind to new lock

resetLock();

// Read in array length and allocate array

intlen = s.readInt();

Object[] elements =newObject[len];

// Read in all elements in the proper order.

for(inti =0;i < len;i++)

elements[i] = s.readObject();

setArray(elements);

}

/**

* Returns a string representation of this list.? The string

* representation consists of the string representations of the list's

* elements in the order they are returned by its iterator, enclosed in

* square brackets ({@code"[]"}).? Adjacent elements are separated by

* the characters {@code", "} (comma and space).? Elements are

* converted to strings as by {@linkString#valueOf(Object)}.

*

*@returna string representation of this list

*/

publicStringtoString() {

returnArrays.toString(getArray());

}

/**

* Compares the specified object with this list for equality.

* Returns {@codetrue} if the specified object is the same object

* as this object, or if it is also a {@linkList} and the sequence

* of elements returned by an {@linkplainList#iterator() iterator}

* over the specified list is the same as the sequence returned by

* an iterator over this list.? The two sequences are considered to

* be the same if they have the same length and corresponding

* elements at the same position in the sequence areequal.

* Two elements {@codee1} and {@codee2} are considered

*equalif {@code(e1==null ? e2==null : e1.equals(e2))}.

*

*@paramothe object to be compared for equality with this list

*@return{@codetrue} if the specified object is equal to this list

*/

public booleanequals(Object o) {

if(o ==this)

return true;

if(!(oinstanceofList))

return false;

List list = (List)(o);

Iterator it = list.iterator();

Object[] elements = getArray();

intlen = elements.length;

for(inti =0;i < len;++i)

if(!it.hasNext() || !eq(elements[i],it.next()))

return false;

if(it.hasNext())

return false;

return true;

}

/**

* Returns the hash code value for this list.

*

*

This implementation uses the definition in {@linkList#hashCode}.

*

*@returnthe hash code value for this list

*/

public inthashCode() {

inthashCode =1;

Object[] elements = getArray();

intlen = elements.length;

for(inti =0;i < len;++i) {

Object obj = elements[i];

hashCode =31*hashCode + (obj==null?0: obj.hashCode());

}

returnhashCode;

}

/**

* Returns an iterator over the elements in this list in proper sequence.

*

*

The returned iterator provides a snapshot of the state of the list

* when the iterator was constructed. No synchronization is needed while

* traversing the iterator. The iterator doesNOTsupport the

* {@coderemove} method.

*

*@returnan iterator over the elements in this list in proper sequence

*/

publicIteratoriterator() {

return newCOWIterator(getArray(),0);

}

/**

* {@inheritDoc}

*

*

The returned iterator provides a snapshot of the state of the list

* when the iterator was constructed. No synchronization is needed while

* traversing the iterator. The iterator doesNOTsupport the

* {@coderemove}, {@codeset} or {@codeadd} methods.

*/

publicListIteratorlistIterator() {

return newCOWIterator(getArray(),0);

}

/**

* {@inheritDoc}

*

*

The returned iterator provides a snapshot of the state of the list

* when the iterator was constructed. No synchronization is needed while

* traversing the iterator. The iterator doesNOTsupport the

* {@coderemove}, {@codeset} or {@codeadd} methods.

*

*@throwsIndexOutOfBoundsException {@inheritDoc}

*/

publicListIteratorlistIterator(intindex) {

Object[] elements = getArray();

intlen = elements.length;

if(index <0|| index > len)

throw newIndexOutOfBoundsException("Index: "+index);

return newCOWIterator(elements,index);

}

/**

* Returns a {@linkSpliterator} over the elements in this list.

*

*

The {@codeSpliterator} reports {@linkSpliterator#IMMUTABLE},

* {@linkSpliterator#ORDERED}, {@linkSpliterator#SIZED}, and

* {@linkSpliterator#SUBSIZED}.

*

*

The spliterator provides a snapshot of the state of the list

* when the spliterator was constructed. No synchronization is needed while

* operating on the spliterator.

*

*@returna {@codeSpliterator} over the elements in this list

*@since1.8

*/

publicSpliteratorspliterator() {

returnSpliterators.spliterator

(getArray(),Spliterator.IMMUTABLE| Spliterator.ORDERED);

}

static final classCOWIteratorimplementsListIterator {

/** Snapshot of the array */

private finalObject[]snapshot;

/** Index of element to be returned by subsequent call to next.? */

private intcursor;

privateCOWIterator(Object[] elements, intinitialCursor) {

cursor= initialCursor;

snapshot= elements;

}

public booleanhasNext() {

returncursor

}

public booleanhasPrevious() {

returncursor>0;

}

@SuppressWarnings("unchecked")

publicEnext() {

if(! hasNext())

throw newNoSuchElementException();

return(E)snapshot[cursor++];

}

@SuppressWarnings("unchecked")

publicEprevious() {

if(! hasPrevious())

throw newNoSuchElementException();

return(E)snapshot[--cursor];

}

public intnextIndex() {

returncursor;

}

public intpreviousIndex() {

returncursor-1;

}

/**

* Not supported. Always throws UnsupportedOperationException.

*@throwsUnsupportedOperationException always; {@coderemove}

*? ? ? ? is not supported by this iterator.

*/

public voidremove() {

throw newUnsupportedOperationException();

}

/**

* Not supported. Always throws UnsupportedOperationException.

*@throwsUnsupportedOperationException always; {@codeset}

*? ? ? ? is not supported by this iterator.

*/

public voidset(Ee) {

throw newUnsupportedOperationException();

}

/**

* Not supported. Always throws UnsupportedOperationException.

*@throwsUnsupportedOperationException always; {@codeadd}

*? ? ? ? is not supported by this iterator.

*/

public voidadd(Ee) {

throw newUnsupportedOperationException();

}

@Override

public voidforEachRemaining(Consumer action) {

Objects.requireNonNull(action);

Object[] elements =snapshot;

final intsize = elements.length;

for(inti =cursor;i < size;i++) {

@SuppressWarnings("unchecked")Ee = (E) elements[i];

action.accept(e);

}

cursor= size;

}

}

/**

* Returns a view of the portion of this list between

* {@codefromIndex}, inclusive, and {@codetoIndex}, exclusive.

* The returned list is backed by this list, so changes in the

* returned list are reflected in this list.

*

*

The semantics of the list returned by this method become

* undefined if the backing list (i.e., this list) is modified in

* any way other than via the returned list.

*

*@paramfromIndexlow endpoint (inclusive) of the subList

*@paramtoIndexhigh endpoint (exclusive) of the subList

*@returna view of the specified range within this list

*@throwsIndexOutOfBoundsException {@inheritDoc}

*/

publicListsubList(intfromIndex, inttoIndex) {

finalReentrantLock lock =this.lock;

lock.lock();

try{

Object[] elements = getArray();

intlen = elements.length;

if(fromIndex <0|| toIndex > len || fromIndex > toIndex)

throw newIndexOutOfBoundsException();

return newCOWSubList(this,fromIndex,toIndex);

}finally{

lock.unlock();

}

}

/**

* Sublist for CopyOnWriteArrayList.

* This class extends AbstractList merely for convenience, to

* avoid having to define addAll, etc. This doesn't hurt, but

* is wasteful.? This class does not need or use modCount

* mechanics in AbstractList, but does need to check for

* concurrent modification using similar mechanics.? On each

* operation, the array that we expect the backing list to use

* is checked and updated.? Since we do this for all of the

* base operations invoked by those defined in AbstractList,

* all is well.? While inefficient, this is not worth

* improving.? The kinds of list operations inherited from

* AbstractList are already so slow on COW sublists that

* adding a bit more space/time doesn't seem even noticeable.

*/

private static classCOWSubList

extendsAbstractList

implementsRandomAccess

{

private finalCopyOnWriteArrayListl;

private final intoffset;

private intsize;

privateObject[]expectedArray;

// only call this holding l's lock

COWSubList(CopyOnWriteArrayList list,

intfromIndex, inttoIndex) {

l= list;

expectedArray=l.getArray();

offset= fromIndex;

size= toIndex - fromIndex;

}

// only call this holding l's lock

private voidcheckForComodification() {

if(l.getArray() !=expectedArray)

throw newConcurrentModificationException();

}

// only call this holding l's lock

private voidrangeCheck(intindex) {

if(index <0|| index >=size)

throw newIndexOutOfBoundsException("Index: "+index+

",Size: "+size);

}

publicEset(intindex,Eelement) {

finalReentrantLock lock =l.lock;

lock.lock();

try{

rangeCheck(index);

checkForComodification();

Ex =l.set(index+offset,element);

expectedArray=l.getArray();

returnx;

}finally{

lock.unlock();

}

}

publicEget(intindex) {

finalReentrantLock lock =l.lock;

lock.lock();

try{

rangeCheck(index);

checkForComodification();

returnl.get(index+offset);

}finally{

lock.unlock();

}

}

public intsize() {

finalReentrantLock lock =l.lock;

lock.lock();

try{

checkForComodification();

returnsize;

}finally{

lock.unlock();

}

}

public voidadd(intindex,Eelement) {

finalReentrantLock lock =l.lock;

lock.lock();

try{

checkForComodification();

if(index <0|| index >size)

throw newIndexOutOfBoundsException();

l.add(index+offset,element);

expectedArray=l.getArray();

size++;

}finally{

lock.unlock();

}

}

public voidclear() {

finalReentrantLock lock =l.lock;

lock.lock();

try{

checkForComodification();

l.removeRange(offset,offset+size);

expectedArray=l.getArray();

size=0;

}finally{

lock.unlock();

}

}

publicEremove(intindex) {

finalReentrantLock lock =l.lock;

lock.lock();

try{

rangeCheck(index);

checkForComodification();

Eresult =l.remove(index+offset);

expectedArray=l.getArray();

size--;

returnresult;

}finally{

lock.unlock();

}

}

public booleanremove(Object o) {

intindex = indexOf(o);

if(index == -1)

return false;

remove(index);

return true;

}

publicIteratoriterator() {

finalReentrantLock lock =l.lock;

lock.lock();

try{

checkForComodification();

return newCOWSubListIterator(l,0,offset,size);

}finally{

lock.unlock();

}

}

publicListIteratorlistIterator(intindex) {

finalReentrantLock lock =l.lock;

lock.lock();

try{

checkForComodification();

if(index <0|| index >size)

throw newIndexOutOfBoundsException("Index: "+index+

", Size: "+size);

return newCOWSubListIterator(l,index,offset,size);

}finally{

lock.unlock();

}

}

publicListsubList(intfromIndex, inttoIndex) {

finalReentrantLock lock =l.lock;

lock.lock();

try{

checkForComodification();

if(fromIndex <0|| toIndex >size|| fromIndex > toIndex)

throw newIndexOutOfBoundsException();

return newCOWSubList(l,fromIndex +offset,

toIndex +offset);

}finally{

lock.unlock();

}

}

public voidforEach(Consumer action) {

if(action ==null)throw newNullPointerException();

intlo =offset;

inthi =offset+size;

Object[] a =expectedArray;

if(l.getArray() != a)

throw newConcurrentModificationException();

if(lo <0|| hi > a.length)

throw newIndexOutOfBoundsException();

for(inti = lo;i < hi;++i) {

@SuppressWarnings("unchecked")Ee = (E) a[i];

action.accept(e);

}

}

public voidreplaceAll(UnaryOperator operator) {

if(operator ==null)throw newNullPointerException();

finalReentrantLock lock =l.lock;

lock.lock();

try{

intlo =offset;

inthi =offset+size;

Object[] elements =expectedArray;

if(l.getArray() != elements)

throw newConcurrentModificationException();

intlen = elements.length;

if(lo <0|| hi > len)

throw newIndexOutOfBoundsException();

Object[] newElements = Arrays.copyOf(elements,len);

for(inti = lo;i < hi;++i) {

@SuppressWarnings("unchecked")Ee = (E) elements[i];

newElements[i] = operator.apply(e);

}

l.setArray(expectedArray= newElements);

}finally{

lock.unlock();

}

}

public voidsort(Comparator c) {

finalReentrantLock lock =l.lock;

lock.lock();

try{

intlo =offset;

inthi =offset+size;

Object[] elements =expectedArray;

if(l.getArray() != elements)

throw newConcurrentModificationException();

intlen = elements.length;

if(lo <0|| hi > len)

throw newIndexOutOfBoundsException();

Object[] newElements = Arrays.copyOf(elements,len);

@SuppressWarnings("unchecked")E[] es = (E[])newElements;

Arrays.sort(es,lo,hi,c);

l.setArray(expectedArray= newElements);

}finally{

lock.unlock();

}

}

public booleanremoveAll(Collection c) {

if(c ==null)throw newNullPointerException();

booleanremoved =false;

finalReentrantLock lock =l.lock;

lock.lock();

try{

intn =size;

if(n >0) {

intlo =offset;

inthi =offset+ n;

Object[] elements =expectedArray;

if(l.getArray() != elements)

throw newConcurrentModificationException();

intlen = elements.length;

if(lo <0|| hi > len)

throw newIndexOutOfBoundsException();

intnewSize =0;

Object[] temp =newObject[n];

for(inti = lo;i < hi;++i) {

Object element = elements[i];

if(!c.contains(element))

temp[newSize++] = element;

}

if(newSize != n) {

Object[] newElements =newObject[len - n + newSize];

System.arraycopy(elements,0,newElements,0,lo);

System.arraycopy(temp,0,newElements,lo,newSize);

System.arraycopy(elements,hi,newElements,

lo + newSize,len - hi);

size= newSize;

removed =true;

l.setArray(expectedArray= newElements);

}

}

}finally{

lock.unlock();

}

returnremoved;

}

public booleanretainAll(Collection c) {

if(c ==null)throw newNullPointerException();

booleanremoved =false;

finalReentrantLock lock =l.lock;

lock.lock();

try{

intn =size;

if(n >0) {

intlo =offset;

inthi =offset+ n;

Object[] elements =expectedArray;

if(l.getArray() != elements)

throw newConcurrentModificationException();

intlen = elements.length;

if(lo <0|| hi > len)

throw newIndexOutOfBoundsException();

intnewSize =0;

Object[] temp =newObject[n];

for(inti = lo;i < hi;++i) {

Object element = elements[i];

if(c.contains(element))

temp[newSize++] = element;

}

if(newSize != n) {

Object[] newElements =newObject[len - n + newSize];

System.arraycopy(elements,0,newElements,0,lo);

System.arraycopy(temp,0,newElements,lo,newSize);

System.arraycopy(elements,hi,newElements,

lo + newSize,len - hi);

size= newSize;

removed =true;

l.setArray(expectedArray= newElements);

}

}

}finally{

lock.unlock();

}

returnremoved;

}

public booleanremoveIf(Predicate filter) {

if(filter ==null)throw newNullPointerException();

booleanremoved =false;

finalReentrantLock lock =l.lock;

lock.lock();

try{

intn =size;

if(n >0) {

intlo =offset;

inthi =offset+ n;

Object[] elements =expectedArray;

if(l.getArray() != elements)

throw newConcurrentModificationException();

intlen = elements.length;

if(lo <0|| hi > len)

throw newIndexOutOfBoundsException();

intnewSize =0;

Object[] temp =newObject[n];

for(inti = lo;i < hi;++i) {

@SuppressWarnings("unchecked")Ee = (E) elements[i];

if(!filter.test(e))

temp[newSize++] = e;

}

if(newSize != n) {

Object[] newElements =newObject[len - n + newSize];

System.arraycopy(elements,0,newElements,0,lo);

System.arraycopy(temp,0,newElements,lo,newSize);

System.arraycopy(elements,hi,newElements,

lo + newSize,len - hi);

size= newSize;

removed =true;

l.setArray(expectedArray= newElements);

}

}

}finally{

lock.unlock();

}

returnremoved;

}

publicSpliteratorspliterator() {

intlo =offset;

inthi =offset+size;

Object[] a =expectedArray;

if(l.getArray() != a)

throw newConcurrentModificationException();

if(lo <0|| hi > a.length)

throw newIndexOutOfBoundsException();

returnSpliterators.spliterator

(a,lo,hi,Spliterator.IMMUTABLE| Spliterator.ORDERED);

}

}

private static classCOWSubListIteratorimplementsListIterator {

private finalListIteratorit;

private final intoffset;

private final intsize;

COWSubListIterator(List l, intindex, intoffset, intsize) {

this.offset= offset;

this.size= size;

it= l.listIterator(index+offset);

}

public booleanhasNext() {

returnnextIndex()

}

publicEnext() {

if(hasNext())

returnit.next();

else

throw newNoSuchElementException();

}

public booleanhasPrevious() {

returnpreviousIndex() >=0;

}

publicEprevious() {

if(hasPrevious())

returnit.previous();

else

throw newNoSuchElementException();

}

public intnextIndex() {

returnit.nextIndex() -offset;

}

public intpreviousIndex() {

returnit.previousIndex() -offset;

}

public voidremove() {

throw newUnsupportedOperationException();

}

public voidset(Ee) {

throw newUnsupportedOperationException();

}

public voidadd(Ee) {

throw newUnsupportedOperationException();

}

@Override

public voidforEachRemaining(Consumer action) {

Objects.requireNonNull(action);

ints =size;

ListIterator i =it;

while(nextIndex() < s) {

action.accept(i.next());

}

}

}

// Support for resetting lock while deserializing

private voidresetLock() {

UNSAFE.putObjectVolatile(this,lockOffset, newReentrantLock());

}

private static finalsun.misc.UnsafeUNSAFE;

private static final longlockOffset;

static{

try{

UNSAFE= sun.misc.Unsafe.getUnsafe();

Class k = CopyOnWriteArrayList.class;

lockOffset=UNSAFE.objectFieldOffset

(k.getDeclaredField("lock"));

}catch(Exception e) {

throw newError(e);

}

}

}

```

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末纲堵,一起剝皮案震驚了整個(gè)濱河市构韵,隨后出現(xiàn)的幾起案子徽龟,更是在濱河造成了極大的恐慌喷斋,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異沧侥,居然都是意外死亡善玫,警方通過(guò)查閱死者的電腦和手機(jī)水援,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)茅郎,“玉大人蜗元,你說(shuō)我怎么就攤上這事∠等撸” “怎么了奕扣?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)毕谴。 經(jīng)常有香客問(wèn)我成畦,道長(zhǎng),這世上最難降的妖魔是什么涝开? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任循帐,我火速辦了婚禮,結(jié)果婚禮上舀武,老公的妹妹穿的比我還像新娘拄养。我一直安慰自己,他們只是感情好银舱,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布瘪匿。 她就那樣靜靜地躺著,像睡著了一般寻馏。 火紅的嫁衣襯著肌膚如雪棋弥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天诚欠,我揣著相機(jī)與錄音顽染,去河邊找鬼。 笑死轰绵,一個(gè)胖子當(dāng)著我的面吹牛粉寞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播左腔,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼唧垦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了液样?” 一聲冷哼從身側(cè)響起振亮,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤巧还,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后坊秸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體狞悲,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年妇斤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丹拯。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡站超,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出乖酬,到底是詐尸還是另有隱情死相,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布咬像,位于F島的核電站算撮,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏县昂。R本人自食惡果不足惜肮柜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望倒彰。 院中可真熱鬧审洞,春花似錦、人聲如沸待讳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)创淡。三九已至痴晦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間琳彩,已是汗流浹背誊酌。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留汁针,地道東北人术辐。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像施无,于是被迫代替她去往敵國(guó)和親辉词。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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