1
25
26 package java.util;
27
28 import java.io.IOException;
29 import java.io.InvalidObjectException;
30 import java.io.ObjectInputStream;
31 import java.io.ObjectOutputStream;
32 import java.io.ObjectStreamException;
33 import java.io.Serializable;
34 import java.util.function.BiFunction;
35 import java.util.function.Function;
36 import java.util.function.Predicate;
37 import java.util.function.UnaryOperator;
38 import jdk.internal.misc.SharedSecrets;
39 import jdk.internal.misc.VM;
40 import jdk.internal.vm.annotation.Stable;
41
42
49 @SuppressWarnings("serial")
50 class ImmutableCollections {
51
57 static final int SALT;
58 static {
59 long nt = System.nanoTime();
60 SALT = (int)((nt >>> 32) ^ nt);
61 }
62
63
64 private ImmutableCollections() { }
65
66
70 static final int EXPAND_FACTOR = 2;
71
72 static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
73
74 static abstract class AbstractImmutableCollection<E> extends AbstractCollection<E> {
75
76 @Override public boolean add(E e) { throw uoe(); }
77 @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
78 @Override public void clear() { throw uoe(); }
79 @Override public boolean remove(Object o) { throw uoe(); }
80 @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
81 @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
82 @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
83 }
84
85
86
87
88 @SuppressWarnings("unchecked")
89 static <E> List<E> listCopy(Collection<? extends E> coll) {
90 if (coll instanceof AbstractImmutableList && coll.getClass() != SubList.class) {
91 return (List<E>)coll;
92 } else {
93 return (List<E>)List.of(coll.toArray());
94 }
95 }
96
97 @SuppressWarnings("unchecked")
98 static <E> List<E> emptyList() {
99 return (List<E>) ListN.EMPTY_LIST;
100 }
101
102 static abstract class AbstractImmutableList<E> extends AbstractImmutableCollection<E>
103 implements List<E>, RandomAccess {
104
105
106 @Override public void add(int index, E element) { throw uoe(); }
107 @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
108 @Override public E remove(int index) { throw uoe(); }
109 @Override public void replaceAll(UnaryOperator<E> operator) { throw uoe(); }
110 @Override public E set(int index, E element) { throw uoe(); }
111 @Override public void sort(Comparator<? super E> c) { throw uoe(); }
112
113 @Override
114 public List<E> subList(int fromIndex, int toIndex) {
115 int size = size();
116 subListRangeCheck(fromIndex, toIndex, size);
117 return SubList.fromList(this, fromIndex, toIndex);
118 }
119
120 static void subListRangeCheck(int fromIndex, int toIndex, int size) {
121 if (fromIndex < 0)
122 throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
123 if (toIndex > size)
124 throw new IndexOutOfBoundsException("toIndex = " + toIndex);
125 if (fromIndex > toIndex)
126 throw new IllegalArgumentException("fromIndex(" + fromIndex +
127 ") > toIndex(" + toIndex + ")");
128 }
129
130 @Override
131 public Iterator<E> iterator() {
132 return new ListItr<E>(this, size());
133 }
134
135 @Override
136 public ListIterator<E> listIterator() {
137 return listIterator(0);
138 }
139
140 @Override
141 public ListIterator<E> listIterator(final int index) {
142 int size = size();
143 if (index < 0 || index > size) {
144 throw outOfBounds(index);
145 }
146 return new ListItr<E>(this, size, index);
147 }
148
149 @Override
150 public boolean equals(Object o) {
151 if (o == this) {
152 return true;
153 }
154
155 if (!(o instanceof List)) {
156 return false;
157 }
158
159 Iterator<?> oit = ((List<?>) o).iterator();
160 for (int i = 0, s = size(); i < s; i++) {
161 if (!oit.hasNext() || !get(i).equals(oit.next())) {
162 return false;
163 }
164 }
165 return !oit.hasNext();
166 }
167
168 @Override
169 public int indexOf(Object o) {
170 Objects.requireNonNull(o);
171 for (int i = 0, s = size(); i < s; i++) {
172 if (o.equals(get(i))) {
173 return i;
174 }
175 }
176 return -1;
177 }
178
179 @Override
180 public int lastIndexOf(Object o) {
181 Objects.requireNonNull(o);
182 for (int i = size() - 1; i >= 0; i--) {
183 if (o.equals(get(i))) {
184 return i;
185 }
186 }
187 return -1;
188 }
189
190 @Override
191 public int hashCode() {
192 int hash = 1;
193 for (int i = 0, s = size(); i < s; i++) {
194 hash = 31 * hash + get(i).hashCode();
195 }
196 return hash;
197 }
198
199 @Override
200 public boolean contains(Object o) {
201 return indexOf(o) >= 0;
202 }
203
204 IndexOutOfBoundsException outOfBounds(int index) {
205 return new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
206 }
207 }
208
209 static final class ListItr<E> implements ListIterator<E> {
210
211 @Stable
212 private final List<E> list;
213
214 @Stable
215 private final int size;
216
217 @Stable
218 private final boolean isListIterator;
219
220 private int cursor;
221
222 ListItr(List<E> list, int size) {
223 this.list = list;
224 this.size = size;
225 this.cursor = 0;
226 isListIterator = false;
227 }
228
229 ListItr(List<E> list, int size, int index) {
230 this.list = list;
231 this.size = size;
232 this.cursor = index;
233 isListIterator = true;
234 }
235
236 public boolean hasNext() {
237 return cursor != size;
238 }
239
240 public E next() {
241 try {
242 int i = cursor;
243 E next = list.get(i);
244 cursor = i + 1;
245 return next;
246 } catch (IndexOutOfBoundsException e) {
247 throw new NoSuchElementException();
248 }
249 }
250
251 public void remove() {
252 throw uoe();
253 }
254
255 public boolean hasPrevious() {
256 if (!isListIterator) {
257 throw uoe();
258 }
259 return cursor != 0;
260 }
261
262 public E previous() {
263 if (!isListIterator) {
264 throw uoe();
265 }
266 try {
267 int i = cursor - 1;
268 E previous = list.get(i);
269 cursor = i;
270 return previous;
271 } catch (IndexOutOfBoundsException e) {
272 throw new NoSuchElementException();
273 }
274 }
275
276 public int nextIndex() {
277 if (!isListIterator) {
278 throw uoe();
279 }
280 return cursor;
281 }
282
283 public int previousIndex() {
284 if (!isListIterator) {
285 throw uoe();
286 }
287 return cursor - 1;
288 }
289
290 public void set(E e) {
291 throw uoe();
292 }
293
294 public void add(E e) {
295 throw uoe();
296 }
297 }
298
299 static final class SubList<E> extends AbstractImmutableList<E>
300 implements RandomAccess {
301
302 @Stable
303 private final List<E> root;
304
305 @Stable
306 private final int offset;
307
308 @Stable
309 private final int size;
310
311 private SubList(List<E> root, int offset, int size) {
312 this.root = root;
313 this.offset = offset;
314 this.size = size;
315 }
316
317
320 static <E> SubList<E> fromSubList(SubList<E> parent, int fromIndex, int toIndex) {
321 return new SubList<>(parent.root, parent.offset + fromIndex, toIndex - fromIndex);
322 }
323
324
328 static <E> SubList<E> fromList(List<E> list, int fromIndex, int toIndex) {
329 return new SubList<>(list, fromIndex, toIndex - fromIndex);
330 }
331
332 public E get(int index) {
333 Objects.checkIndex(index, size);
334 return root.get(offset + index);
335 }
336
337 public int size() {
338 return size;
339 }
340
341 public Iterator<E> iterator() {
342 return new ListItr<>(this, size());
343 }
344
345 public ListIterator<E> listIterator(int index) {
346 rangeCheck(index);
347 return new ListItr<>(this, size(), index);
348 }
349
350 public List<E> subList(int fromIndex, int toIndex) {
351 subListRangeCheck(fromIndex, toIndex, size);
352 return SubList.fromSubList(this, fromIndex, toIndex);
353 }
354
355 private void rangeCheck(int index) {
356 if (index < 0 || index > size) {
357 throw outOfBounds(index);
358 }
359 }
360 }
361
362 static final class List12<E> extends AbstractImmutableList<E>
363 implements Serializable {
364
365 @Stable
366 private final E e0;
367
368 @Stable
369 private final E e1;
370
371 List12(E e0) {
372 this.e0 = Objects.requireNonNull(e0);
373 this.e1 = null;
374 }
375
376 List12(E e0, E e1) {
377 this.e0 = Objects.requireNonNull(e0);
378 this.e1 = Objects.requireNonNull(e1);
379 }
380
381 @Override
382 public int size() {
383 return e1 != null ? 2 : 1;
384 }
385
386 @Override
387 public E get(int index) {
388 if (index == 0) {
389 return e0;
390 } else if (index == 1 && e1 != null) {
391 return e1;
392 }
393 throw outOfBounds(index);
394 }
395
396 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
397 throw new InvalidObjectException("not serial proxy");
398 }
399
400 private Object writeReplace() {
401 if (e1 == null) {
402 return new CollSer(CollSer.IMM_LIST, e0);
403 } else {
404 return new CollSer(CollSer.IMM_LIST, e0, e1);
405 }
406 }
407
408 }
409
410 static final class ListN<E> extends AbstractImmutableList<E>
411 implements Serializable {
412
413
414 static @Stable List<?> EMPTY_LIST;
415
416 static {
417 VM.initializeFromArchive(ListN.class);
418 if (EMPTY_LIST == null) {
419 EMPTY_LIST = new ListN<>();
420 }
421 }
422
423 @Stable
424 private final E[] elements;
425
426 @SafeVarargs
427 ListN(E... input) {
428
429 @SuppressWarnings("unchecked")
430 E[] tmp = (E[])new Object[input.length];
431 for (int i = 0; i < input.length; i++) {
432 tmp[i] = Objects.requireNonNull(input[i]);
433 }
434 elements = tmp;
435 }
436
437 @Override
438 public boolean isEmpty() {
439 return size() == 0;
440 }
441
442 @Override
443 public int size() {
444 return elements.length;
445 }
446
447 @Override
448 public E get(int index) {
449 return elements[index];
450 }
451
452 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
453 throw new InvalidObjectException("not serial proxy");
454 }
455
456 private Object writeReplace() {
457 return new CollSer(CollSer.IMM_LIST, elements);
458 }
459 }
460
461
462
463 static abstract class AbstractImmutableSet<E> extends AbstractImmutableCollection<E>
464 implements Set<E> {
465
466 @Override
467 public boolean equals(Object o) {
468 if (o == this) {
469 return true;
470 } else if (!(o instanceof Set)) {
471 return false;
472 }
473
474 Collection<?> c = (Collection<?>) o;
475 if (c.size() != size()) {
476 return false;
477 }
478 for (Object e : c) {
479 if (e == null || !contains(e)) {
480 return false;
481 }
482 }
483 return true;
484 }
485
486 @Override
487 public abstract int hashCode();
488 }
489
490 @SuppressWarnings("unchecked")
491 static <E> Set<E> emptySet() {
492 return (Set<E>) SetN.EMPTY_SET;
493 }
494
495 static final class Set12<E> extends AbstractImmutableSet<E>
496 implements Serializable {
497
498 @Stable
499 final E e0;
500 @Stable
501 final E e1;
502
503 Set12(E e0) {
504 this.e0 = Objects.requireNonNull(e0);
505 this.e1 = null;
506 }
507
508 Set12(E e0, E e1) {
509 if (e0.equals(Objects.requireNonNull(e1))) {
510 throw new IllegalArgumentException("duplicate element: " + e0);
511 }
512
513 this.e0 = e0;
514 this.e1 = e1;
515 }
516
517 @Override
518 public int size() {
519 return (e1 == null) ? 1 : 2;
520 }
521
522 @Override
523 public boolean contains(Object o) {
524 return o.equals(e0) || o.equals(e1);
525 }
526
527 @Override
528 public int hashCode() {
529 return e0.hashCode() + (e1 == null ? 0 : e1.hashCode());
530 }
531
532 @Override
533 public Iterator<E> iterator() {
534 return new Iterator<>() {
535 private int idx = size();
536
537 @Override
538 public boolean hasNext() {
539 return idx > 0;
540 }
541
542 @Override
543 public E next() {
544 if (idx == 1) {
545 idx = 0;
546 return SALT >= 0 || e1 == null ? e0 : e1;
547 } else if (idx == 2) {
548 idx = 1;
549 return SALT >= 0 ? e1 : e0;
550 } else {
551 throw new NoSuchElementException();
552 }
553 }
554 };
555 }
556
557 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
558 throw new InvalidObjectException("not serial proxy");
559 }
560
561 private Object writeReplace() {
562 if (e1 == null) {
563 return new CollSer(CollSer.IMM_SET, e0);
564 } else {
565 return new CollSer(CollSer.IMM_SET, e0, e1);
566 }
567 }
568 }
569
570
576 static final class SetN<E> extends AbstractImmutableSet<E>
577 implements Serializable {
578
579
580 static @Stable Set<?> EMPTY_SET;
581
582 static {
583 VM.initializeFromArchive(SetN.class);
584 if (EMPTY_SET == null) {
585 EMPTY_SET = new SetN<>();
586 }
587 }
588
589 @Stable
590 final E[] elements;
591 @Stable
592 final int size;
593
594 @SafeVarargs
595 @SuppressWarnings("unchecked")
596 SetN(E... input) {
597 size = input.length;
598
599 elements = (E[])new Object[EXPAND_FACTOR * input.length];
600 for (int i = 0; i < input.length; i++) {
601 E e = input[i];
602 int idx = probe(e);
603 if (idx >= 0) {
604 throw new IllegalArgumentException("duplicate element: " + e);
605 } else {
606 elements[-(idx + 1)] = e;
607 }
608 }
609 }
610
611 @Override
612 public int size() {
613 return size;
614 }
615
616 @Override
617 public boolean contains(Object o) {
618 Objects.requireNonNull(o);
619 return size > 0 && probe(o) >= 0;
620 }
621
622 private final class SetNIterator implements Iterator<E> {
623
624 private int remaining;
625
626 private int idx;
627
628 SetNIterator() {
629 remaining = size();
630 if (remaining > 0) {
631 idx = Math.floorMod(SALT, elements.length);
632 }
633 }
634
635 @Override
636 public boolean hasNext() {
637 return remaining > 0;
638 }
639
640 private int nextIndex() {
641 int idx = this.idx;
642 if (SALT >= 0) {
643 if (++idx >= elements.length) {
644 idx = 0;
645 }
646 } else {
647 if (--idx < 0) {
648 idx = elements.length - 1;
649 }
650 }
651 return this.idx = idx;
652 }
653
654 @Override
655 public E next() {
656 if (hasNext()) {
657 E element;
658
659 while ((element = elements[nextIndex()]) == null) {}
660 remaining--;
661 return element;
662 } else {
663 throw new NoSuchElementException();
664 }
665 }
666 }
667
668 @Override
669 public Iterator<E> iterator() {
670 return new SetNIterator();
671 }
672
673 @Override
674 public int hashCode() {
675 int h = 0;
676 for (E e : elements) {
677 if (e != null) {
678 h += e.hashCode();
679 }
680 }
681 return h;
682 }
683
684
685
686
687
688 private int probe(Object pe) {
689 int idx = Math.floorMod(pe.hashCode(), elements.length);
690 while (true) {
691 E ee = elements[idx];
692 if (ee == null) {
693 return -idx - 1;
694 } else if (pe.equals(ee)) {
695 return idx;
696 } else if (++idx == elements.length) {
697 idx = 0;
698 }
699 }
700 }
701
702 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
703 throw new InvalidObjectException("not serial proxy");
704 }
705
706 private Object writeReplace() {
707 Object[] array = new Object[size];
708 int dest = 0;
709 for (Object o : elements) {
710 if (o != null) {
711 array[dest++] = o;
712 }
713 }
714 return new CollSer(CollSer.IMM_SET, array);
715 }
716 }
717
718
719
720 @SuppressWarnings("unchecked")
721 static <K,V> Map<K,V> emptyMap() {
722 return (Map<K,V>) MapN.EMPTY_MAP;
723 }
724
725 abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable {
726 @Override public void clear() { throw uoe(); }
727 @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
728 @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); }
729 @Override public V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
730 @Override public V merge(K key, V value, BiFunction<? super V,? super V,? extends V> rf) { throw uoe(); }
731 @Override public V put(K key, V value) { throw uoe(); }
732 @Override public void putAll(Map<? extends K,? extends V> m) { throw uoe(); }
733 @Override public V putIfAbsent(K key, V value) { throw uoe(); }
734 @Override public V remove(Object key) { throw uoe(); }
735 @Override public boolean remove(Object key, Object value) { throw uoe(); }
736 @Override public V replace(K key, V value) { throw uoe(); }
737 @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); }
738 @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
739 }
740
741 static final class Map1<K,V> extends AbstractImmutableMap<K,V> {
742 @Stable
743 private final K k0;
744 @Stable
745 private final V v0;
746
747 Map1(K k0, V v0) {
748 this.k0 = Objects.requireNonNull(k0);
749 this.v0 = Objects.requireNonNull(v0);
750 }
751
752 @Override
753 public Set<Map.Entry<K,V>> entrySet() {
754 return Set.of(new KeyValueHolder<>(k0, v0));
755 }
756
757 @Override
758 public V get(Object o) {
759 return o.equals(k0) ? v0 : null;
760 }
761
762 @Override
763 public boolean containsKey(Object o) {
764 return o.equals(k0);
765 }
766
767 @Override
768 public boolean containsValue(Object o) {
769 return o.equals(v0);
770 }
771
772 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
773 throw new InvalidObjectException("not serial proxy");
774 }
775
776 private Object writeReplace() {
777 return new CollSer(CollSer.IMM_MAP, k0, v0);
778 }
779
780 @Override
781 public int hashCode() {
782 return k0.hashCode() ^ v0.hashCode();
783 }
784 }
785
786
795 static final class MapN<K,V> extends AbstractImmutableMap<K,V> {
796
797
798 static @Stable Map<?,?> EMPTY_MAP;
799
800 static {
801 VM.initializeFromArchive(MapN.class);
802 if (EMPTY_MAP == null) {
803 EMPTY_MAP = new MapN<>();
804 }
805 }
806
807 @Stable
808 final Object[] table;
809
810 @Stable
811 final int size;
812
813 MapN(Object... input) {
814 if ((input.length & 1) != 0) {
815 throw new InternalError("length is odd");
816 }
817 size = input.length >> 1;
818
819 int len = EXPAND_FACTOR * input.length;
820 len = (len + 1) & ~1;
821 table = new Object[len];
822
823 for (int i = 0; i < input.length; i += 2) {
824 @SuppressWarnings("unchecked")
825 K k = Objects.requireNonNull((K)input[i]);
826 @SuppressWarnings("unchecked")
827 V v = Objects.requireNonNull((V)input[i+1]);
828 int idx = probe(k);
829 if (idx >= 0) {
830 throw new IllegalArgumentException("duplicate key: " + k);
831 } else {
832 int dest = -(idx + 1);
833 table[dest] = k;
834 table[dest+1] = v;
835 }
836 }
837 }
838
839 @Override
840 public boolean containsKey(Object o) {
841 Objects.requireNonNull(o);
842 return size > 0 && probe(o) >= 0;
843 }
844
845 @Override
846 public boolean containsValue(Object o) {
847 Objects.requireNonNull(o);
848 for (int i = 1; i < table.length; i += 2) {
849 Object v = table[i];
850 if (v != null && o.equals(v)) {
851 return true;
852 }
853 }
854 return false;
855 }
856
857 @Override
858 public int hashCode() {
859 int hash = 0;
860 for (int i = 0; i < table.length; i += 2) {
861 Object k = table[i];
862 if (k != null) {
863 hash += k.hashCode() ^ table[i + 1].hashCode();
864 }
865 }
866 return hash;
867 }
868
869 @Override
870 @SuppressWarnings("unchecked")
871 public V get(Object o) {
872 if (size == 0) {
873 Objects.requireNonNull(o);
874 return null;
875 }
876 int i = probe(o);
877 if (i >= 0) {
878 return (V)table[i+1];
879 } else {
880 return null;
881 }
882 }
883
884 @Override
885 public int size() {
886 return size;
887 }
888
889 class MapNIterator implements Iterator<Map.Entry<K,V>> {
890
891 private int remaining;
892
893 private int idx;
894
895 MapNIterator() {
896 remaining = size();
897 if (remaining > 0) {
898 idx = Math.floorMod(SALT, table.length >> 1) << 1;
899 }
900 }
901
902 @Override
903 public boolean hasNext() {
904 return remaining > 0;
905 }
906
907 private int nextIndex() {
908 int idx = this.idx;
909 if (SALT >= 0) {
910 if ((idx += 2) >= table.length) {
911 idx = 0;
912 }
913 } else {
914 if ((idx -= 2) < 0) {
915 idx = table.length - 2;
916 }
917 }
918 return this.idx = idx;
919 }
920
921 @Override
922 public Map.Entry<K,V> next() {
923 if (hasNext()) {
924 while (table[nextIndex()] == null) {}
925 @SuppressWarnings("unchecked")
926 Map.Entry<K,V> e =
927 new KeyValueHolder<>((K)table[idx], (V)table[idx+1]);
928 remaining--;
929 return e;
930 } else {
931 throw new NoSuchElementException();
932 }
933 }
934 }
935
936 @Override
937 public Set<Map.Entry<K,V>> entrySet() {
938 return new AbstractSet<>() {
939 @Override
940 public int size() {
941 return MapN.this.size;
942 }
943
944 @Override
945 public Iterator<Map.Entry<K,V>> iterator() {
946 return new MapNIterator();
947 }
948 };
949 }
950
951
952
953
954
955 private int probe(Object pk) {
956 int idx = Math.floorMod(pk.hashCode(), table.length >> 1) << 1;
957 while (true) {
958 @SuppressWarnings("unchecked")
959 K ek = (K)table[idx];
960 if (ek == null) {
961 return -idx - 1;
962 } else if (pk.equals(ek)) {
963 return idx;
964 } else if ((idx += 2) == table.length) {
965 idx = 0;
966 }
967 }
968 }
969
970 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
971 throw new InvalidObjectException("not serial proxy");
972 }
973
974 private Object writeReplace() {
975 Object[] array = new Object[2 * size];
976 int len = table.length;
977 int dest = 0;
978 for (int i = 0; i < len; i += 2) {
979 if (table[i] != null) {
980 array[dest++] = table[i];
981 array[dest++] = table[i+1];
982 }
983 }
984 return new CollSer(CollSer.IMM_MAP, array);
985 }
986 }
987 }
988
989
990
991
997 final class CollSer implements Serializable {
998 private static final long serialVersionUID = 6309168927139932177L;
999
1000 static final int IMM_LIST = 1;
1001 static final int IMM_SET = 2;
1002 static final int IMM_MAP = 3;
1003
1004
1031 private final int tag;
1032
1033
1037 private transient Object[] array;
1038
1039 CollSer(int t, Object... a) {
1040 tag = t;
1041 array = a;
1042 }
1043
1044
1058 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
1059 ois.defaultReadObject();
1060 int len = ois.readInt();
1061
1062 if (len < 0) {
1063 throw new InvalidObjectException("negative length " + len);
1064 }
1065
1066 SharedSecrets.getJavaObjectInputStreamAccess().checkArray(ois, Object[].class, len);
1067 Object[] a = new Object[len];
1068 for (int i = 0; i < len; i++) {
1069 a[i] = ois.readObject();
1070 }
1071
1072 array = a;
1073 }
1074
1075
1087 private void writeObject(ObjectOutputStream oos) throws IOException {
1088 oos.defaultWriteObject();
1089 oos.writeInt(array.length);
1090 for (int i = 0; i < array.length; i++) {
1091 oos.writeObject(array[i]);
1092 }
1093 }
1094
1095
1113 private Object readResolve() throws ObjectStreamException {
1114 try {
1115 if (array == null) {
1116 throw new InvalidObjectException("null array");
1117 }
1118
1119
1120
1121 switch (tag & 0xff) {
1122 case IMM_LIST:
1123 return List.of(array);
1124 case IMM_SET:
1125 return Set.of(array);
1126 case IMM_MAP:
1127 if (array.length == 0) {
1128 return ImmutableCollections.emptyMap();
1129 } else if (array.length == 2) {
1130 return new ImmutableCollections.Map1<>(array[0], array[1]);
1131 } else {
1132 return new ImmutableCollections.MapN<>(array);
1133 }
1134 default:
1135 throw new InvalidObjectException(String.format("invalid flags 0x%x", tag));
1136 }
1137 } catch (NullPointerException|IllegalArgumentException ex) {
1138 InvalidObjectException ioe = new InvalidObjectException("invalid object");
1139 ioe.initCause(ex);
1140 throw ioe;
1141 }
1142 }
1143 }
1144