Path: blob/master/src/java.base/share/classes/java/util/EnumSet.java
41152 views
/*1* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.util;2627import jdk.internal.access.SharedSecrets;2829/**30* A specialized {@link Set} implementation for use with enum types. All of31* the elements in an enum set must come from a single enum type that is32* specified, explicitly or implicitly, when the set is created. Enum sets33* are represented internally as bit vectors. This representation is34* extremely compact and efficient. The space and time performance of this35* class should be good enough to allow its use as a high-quality, typesafe36* alternative to traditional {@code int}-based "bit flags." Even bulk37* operations (such as {@code containsAll} and {@code retainAll}) should38* run very quickly if their argument is also an enum set.39*40* <p>The iterator returned by the {@code iterator} method traverses the41* elements in their <i>natural order</i> (the order in which the enum42* constants are declared). The returned iterator is <i>weakly43* consistent</i>: it will never throw {@link ConcurrentModificationException}44* and it may or may not show the effects of any modifications to the set that45* occur while the iteration is in progress.46*47* <p>Null elements are not permitted. Attempts to insert a null element48* will throw {@link NullPointerException}. Attempts to test for the49* presence of a null element or to remove one will, however, function50* properly.51*52* <P>Like most collection implementations, {@code EnumSet} is not53* synchronized. If multiple threads access an enum set concurrently, and at54* least one of the threads modifies the set, it should be synchronized55* externally. This is typically accomplished by synchronizing on some56* object that naturally encapsulates the enum set. If no such object exists,57* the set should be "wrapped" using the {@link Collections#synchronizedSet}58* method. This is best done at creation time, to prevent accidental59* unsynchronized access:60*61* <pre>62* Set<MyEnum> s = Collections.synchronizedSet(EnumSet.noneOf(MyEnum.class));63* </pre>64*65* <p>Implementation note: All basic operations execute in constant time.66* They are likely (though not guaranteed) to be much faster than their67* {@link HashSet} counterparts. Even bulk operations execute in68* constant time if their argument is also an enum set.69*70* <p>This class is a member of the71* <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">72* Java Collections Framework</a>.73*74* @author Josh Bloch75* @since 1.576* @see EnumMap77*/78public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>79implements Cloneable, java.io.Serializable80{81// declare EnumSet.class serialization compatibility with JDK 882@java.io.Serial83private static final long serialVersionUID = 1009687484059888093L;8485/**86* The class of all the elements of this set.87*/88final transient Class<E> elementType;8990/**91* All of the values comprising E. (Cached for performance.)92*/93final transient Enum<?>[] universe;9495EnumSet(Class<E>elementType, Enum<?>[] universe) {96this.elementType = elementType;97this.universe = universe;98}99100/**101* Creates an empty enum set with the specified element type.102*103* @param <E> The class of the elements in the set104* @param elementType the class object of the element type for this enum105* set106* @return An empty enum set of the specified type.107* @throws NullPointerException if {@code elementType} is null108*/109public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {110Enum<?>[] universe = getUniverse(elementType);111if (universe == null)112throw new ClassCastException(elementType + " not an enum");113114if (universe.length <= 64)115return new RegularEnumSet<>(elementType, universe);116else117return new JumboEnumSet<>(elementType, universe);118}119120/**121* Creates an enum set containing all of the elements in the specified122* element type.123*124* @param <E> The class of the elements in the set125* @param elementType the class object of the element type for this enum126* set127* @return An enum set containing all the elements in the specified type.128* @throws NullPointerException if {@code elementType} is null129*/130public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) {131EnumSet<E> result = noneOf(elementType);132result.addAll();133return result;134}135136/**137* Adds all of the elements from the appropriate enum type to this enum138* set, which is empty prior to the call.139*/140abstract void addAll();141142/**143* Creates an enum set with the same element type as the specified enum144* set, initially containing the same elements (if any).145*146* @param <E> The class of the elements in the set147* @param s the enum set from which to initialize this enum set148* @return A copy of the specified enum set.149* @throws NullPointerException if {@code s} is null150*/151public static <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s) {152return s.clone();153}154155/**156* Creates an enum set initialized from the specified collection. If157* the specified collection is an {@code EnumSet} instance, this static158* factory method behaves identically to {@link #copyOf(EnumSet)}.159* Otherwise, the specified collection must contain at least one element160* (in order to determine the new enum set's element type).161*162* @param <E> The class of the elements in the collection163* @param c the collection from which to initialize this enum set164* @return An enum set initialized from the given collection.165* @throws IllegalArgumentException if {@code c} is not an166* {@code EnumSet} instance and contains no elements167* @throws NullPointerException if {@code c} is null168*/169public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c) {170if (c instanceof EnumSet) {171return ((EnumSet<E>)c).clone();172} else {173if (c.isEmpty())174throw new IllegalArgumentException("Collection is empty");175Iterator<E> i = c.iterator();176E first = i.next();177EnumSet<E> result = EnumSet.of(first);178while (i.hasNext())179result.add(i.next());180return result;181}182}183184/**185* Creates an enum set with the same element type as the specified enum186* set, initially containing all the elements of this type that are187* <i>not</i> contained in the specified set.188*189* @param <E> The class of the elements in the enum set190* @param s the enum set from whose complement to initialize this enum set191* @return The complement of the specified set in this set192* @throws NullPointerException if {@code s} is null193*/194public static <E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s) {195EnumSet<E> result = copyOf(s);196result.complement();197return result;198}199200/**201* Creates an enum set initially containing the specified element.202*203* Overloadings of this method exist to initialize an enum set with204* one through five elements. A sixth overloading is provided that205* uses the varargs feature. This overloading may be used to create206* an enum set initially containing an arbitrary number of elements, but207* is likely to run slower than the overloadings that do not use varargs.208*209* @param <E> The class of the specified element and of the set210* @param e the element that this set is to contain initially211* @throws NullPointerException if {@code e} is null212* @return an enum set initially containing the specified element213*/214public static <E extends Enum<E>> EnumSet<E> of(E e) {215EnumSet<E> result = noneOf(e.getDeclaringClass());216result.add(e);217return result;218}219220/**221* Creates an enum set initially containing the specified elements.222*223* Overloadings of this method exist to initialize an enum set with224* one through five elements. A sixth overloading is provided that225* uses the varargs feature. This overloading may be used to create226* an enum set initially containing an arbitrary number of elements, but227* is likely to run slower than the overloadings that do not use varargs.228*229* @param <E> The class of the parameter elements and of the set230* @param e1 an element that this set is to contain initially231* @param e2 another element that this set is to contain initially232* @throws NullPointerException if any parameters are null233* @return an enum set initially containing the specified elements234*/235public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2) {236EnumSet<E> result = noneOf(e1.getDeclaringClass());237result.add(e1);238result.add(e2);239return result;240}241242/**243* Creates an enum set initially containing the specified elements.244*245* Overloadings of this method exist to initialize an enum set with246* one through five elements. A sixth overloading is provided that247* uses the varargs feature. This overloading may be used to create248* an enum set initially containing an arbitrary number of elements, but249* is likely to run slower than the overloadings that do not use varargs.250*251* @param <E> The class of the parameter elements and of the set252* @param e1 an element that this set is to contain initially253* @param e2 another element that this set is to contain initially254* @param e3 another element that this set is to contain initially255* @throws NullPointerException if any parameters are null256* @return an enum set initially containing the specified elements257*/258public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3) {259EnumSet<E> result = noneOf(e1.getDeclaringClass());260result.add(e1);261result.add(e2);262result.add(e3);263return result;264}265266/**267* Creates an enum set initially containing the specified elements.268*269* Overloadings of this method exist to initialize an enum set with270* one through five elements. A sixth overloading is provided that271* uses the varargs feature. This overloading may be used to create272* an enum set initially containing an arbitrary number of elements, but273* is likely to run slower than the overloadings that do not use varargs.274*275* @param <E> The class of the parameter elements and of the set276* @param e1 an element that this set is to contain initially277* @param e2 another element that this set is to contain initially278* @param e3 another element that this set is to contain initially279* @param e4 another element that this set is to contain initially280* @throws NullPointerException if any parameters are null281* @return an enum set initially containing the specified elements282*/283public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4) {284EnumSet<E> result = noneOf(e1.getDeclaringClass());285result.add(e1);286result.add(e2);287result.add(e3);288result.add(e4);289return result;290}291292/**293* Creates an enum set initially containing the specified elements.294*295* Overloadings of this method exist to initialize an enum set with296* one through five elements. A sixth overloading is provided that297* uses the varargs feature. This overloading may be used to create298* an enum set initially containing an arbitrary number of elements, but299* is likely to run slower than the overloadings that do not use varargs.300*301* @param <E> The class of the parameter elements and of the set302* @param e1 an element that this set is to contain initially303* @param e2 another element that this set is to contain initially304* @param e3 another element that this set is to contain initially305* @param e4 another element that this set is to contain initially306* @param e5 another element that this set is to contain initially307* @throws NullPointerException if any parameters are null308* @return an enum set initially containing the specified elements309*/310public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4,311E e5)312{313EnumSet<E> result = noneOf(e1.getDeclaringClass());314result.add(e1);315result.add(e2);316result.add(e3);317result.add(e4);318result.add(e5);319return result;320}321322/**323* Creates an enum set initially containing the specified elements.324* This factory, whose parameter list uses the varargs feature, may325* be used to create an enum set initially containing an arbitrary326* number of elements, but it is likely to run slower than the overloadings327* that do not use varargs.328*329* @param <E> The class of the parameter elements and of the set330* @param first an element that the set is to contain initially331* @param rest the remaining elements the set is to contain initially332* @throws NullPointerException if any of the specified elements are null,333* or if {@code rest} is null334* @return an enum set initially containing the specified elements335*/336@SafeVarargs337public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest) {338EnumSet<E> result = noneOf(first.getDeclaringClass());339result.add(first);340for (E e : rest)341result.add(e);342return result;343}344345/**346* Creates an enum set initially containing all of the elements in the347* range defined by the two specified endpoints. The returned set will348* contain the endpoints themselves, which may be identical but must not349* be out of order.350*351* @param <E> The class of the parameter elements and of the set352* @param from the first element in the range353* @param to the last element in the range354* @throws NullPointerException if {@code from} or {@code to} are null355* @throws IllegalArgumentException if {@code from.compareTo(to) > 0}356* @return an enum set initially containing all of the elements in the357* range defined by the two specified endpoints358*/359public static <E extends Enum<E>> EnumSet<E> range(E from, E to) {360if (from.compareTo(to) > 0)361throw new IllegalArgumentException(from + " > " + to);362EnumSet<E> result = noneOf(from.getDeclaringClass());363result.addRange(from, to);364return result;365}366367/**368* Adds the specified range to this enum set, which is empty prior369* to the call.370*/371abstract void addRange(E from, E to);372373/**374* Returns a copy of this set.375*376* @return a copy of this set377*/378@SuppressWarnings("unchecked")379public EnumSet<E> clone() {380try {381return (EnumSet<E>) super.clone();382} catch(CloneNotSupportedException e) {383throw new AssertionError(e);384}385}386387/**388* Complements the contents of this enum set.389*/390abstract void complement();391392/**393* Throws an exception if e is not of the correct type for this enum set.394*/395final void typeCheck(E e) {396Class<?> eClass = e.getClass();397if (eClass != elementType && eClass.getSuperclass() != elementType)398throw new ClassCastException(eClass + " != " + elementType);399}400401/**402* Returns all of the values comprising E.403* The result is uncloned, cached, and shared by all callers.404*/405private static <E extends Enum<E>> E[] getUniverse(Class<E> elementType) {406return SharedSecrets.getJavaLangAccess()407.getEnumConstantsShared(elementType);408}409410/**411* This class is used to serialize all EnumSet instances, regardless of412* implementation type. It captures their "logical contents" and they413* are reconstructed using public static factories. This is necessary414* to ensure that the existence of a particular implementation type is415* an implementation detail.416*417* @serial include418*/419private static class SerializationProxy<E extends Enum<E>>420implements java.io.Serializable421{422423private static final Enum<?>[] ZERO_LENGTH_ENUM_ARRAY = new Enum<?>[0];424425/**426* The element type of this enum set.427*428* @serial429*/430private final Class<E> elementType;431432/**433* The elements contained in this enum set.434*435* @serial436*/437private final Enum<?>[] elements;438439SerializationProxy(EnumSet<E> set) {440elementType = set.elementType;441elements = set.toArray(ZERO_LENGTH_ENUM_ARRAY);442}443444/**445* Returns an {@code EnumSet} object with initial state446* held by this proxy.447*448* @return a {@code EnumSet} object with initial state449* held by this proxy450*/451@SuppressWarnings("unchecked")452@java.io.Serial453private Object readResolve() {454// instead of cast to E, we should perhaps use elementType.cast()455// to avoid injection of forged stream, but it will slow the456// implementation457EnumSet<E> result = EnumSet.noneOf(elementType);458for (Enum<?> e : elements)459result.add((E)e);460return result;461}462463@java.io.Serial464private static final long serialVersionUID = 362491234563181265L;465}466467/**468* Returns a469* <a href="{@docRoot}/serialized-form.html#java.util.EnumSet.SerializationProxy">470* SerializationProxy</a>471* representing the state of this instance.472*473* @return a {@link SerializationProxy}474* representing the state of this instance475*/476@java.io.Serial477Object writeReplace() {478return new SerializationProxy<>(this);479}480481/**482* Throws {@code InvalidObjectException}.483* @param s the stream484* @throws java.io.InvalidObjectException always485*/486@java.io.Serial487private void readObject(java.io.ObjectInputStream s)488throws java.io.InvalidObjectException {489throw new java.io.InvalidObjectException("Proxy required");490}491492/**493* Throws {@code InvalidObjectException}.494* @throws java.io.InvalidObjectException always495*/496@java.io.Serial497private void readObjectNoData()498throws java.io.InvalidObjectException {499throw new java.io.InvalidObjectException("Proxy required");500}501}502503504