1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package java.util; 17 18import java.io.Serializable; 19 20/** 21 * An EnumSet is a specialized Set to be used with enums as keys. 22 */ 23public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E> 24 implements Cloneable, Serializable { 25 private static final long serialVersionUID = 1009687484059888093L; 26 27 final Class<E> elementClass; 28 29 EnumSet(Class<E> cls) { 30 elementClass = cls; 31 } 32 33 /** 34 * Creates an empty enum set. The permitted elements are of type 35 * Class<E>. 36 * 37 * @param elementType 38 * the class object for the elements contained. 39 * @return an empty enum set, with permitted elements of type {@code 40 * elementType}. 41 * @throws ClassCastException 42 * if the specified element type is not and enum type. 43 */ 44 public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) { 45 if (!elementType.isEnum()) { 46 throw new ClassCastException(elementType.getClass().getName() + " is not an Enum"); 47 } 48 E[] enums = Enum.getSharedConstants(elementType); 49 if (enums.length <= 64) { 50 return new MiniEnumSet<E>(elementType, enums); 51 } 52 return new HugeEnumSet<E>(elementType, enums); 53 } 54 55 /** 56 * Creates an enum set filled with all the enum elements of the specified 57 * {@code elementType}. 58 * 59 * @param elementType 60 * the class object for the elements contained. 61 * @return an enum set with elements solely from the specified element type. 62 * @throws ClassCastException 63 * if the specified element type is not and enum type. 64 */ 65 public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) { 66 EnumSet<E> set = noneOf(elementType); 67 set.complement(); 68 return set; 69 } 70 71 /** 72 * Creates an enum set. All the contained elements are of type 73 * Class<E>, and the contained elements are the same as those 74 * contained in {@code s}. 75 * 76 * @param s 77 * the enum set from which to copy. 78 * @return an enum set with all the elements from the specified enum set. 79 * @throws ClassCastException 80 * if the specified element type is not and enum type. 81 */ 82 public static <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s) { 83 EnumSet<E> set = EnumSet.noneOf(s.elementClass); 84 set.addAll(s); 85 return set; 86 } 87 88 /** 89 * Creates an enum set. The contained elements are the same as those 90 * contained in collection {@code c}. If c is an enum set, invoking this 91 * method is the same as invoking {@link #copyOf(EnumSet)}. 92 * 93 * @param c 94 * the collection from which to copy. if it is not an enum set, 95 * it must not be empty. 96 * @return an enum set with all the elements from the specified collection. 97 * @throws IllegalArgumentException 98 * if c is not an enum set and contains no elements at all. 99 * @throws NullPointerException 100 * if {@code c} is {@code null}. 101 */ 102 public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c) { 103 if (c instanceof EnumSet) { 104 return copyOf((EnumSet<E>) c); 105 } 106 if (c.isEmpty()) { 107 throw new IllegalArgumentException("empty collection"); 108 } 109 Iterator<E> iterator = c.iterator(); 110 E element = iterator.next(); 111 EnumSet<E> set = EnumSet.noneOf(element.getDeclaringClass()); 112 set.add(element); 113 while (iterator.hasNext()) { 114 set.add(iterator.next()); 115 } 116 return set; 117 } 118 119 /** 120 * Creates an enum set. All the contained elements complement those from the 121 * specified enum set. 122 * 123 * @param s 124 * the specified enum set. 125 * @return an enum set with all the elements complementary to those from the 126 * specified enum set. 127 * @throws NullPointerException 128 * if {@code s} is {@code null}. 129 */ 130 public static <E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s) { 131 EnumSet<E> set = EnumSet.noneOf(s.elementClass); 132 set.addAll(s); 133 set.complement(); 134 return set; 135 } 136 137 abstract void complement(); 138 139 /** 140 * Creates a new enum set, containing only the specified element. There are 141 * six overloadings of the method. They accept from one to five elements 142 * respectively. The sixth one receives an arbitrary number of elements, and 143 * runs slower than those that only receive a fixed number of elements. 144 * 145 * @param e 146 * the element to be initially contained. 147 * @return an enum set containing the specified element. 148 * @throws NullPointerException 149 * if {@code e} is {@code null}. 150 */ 151 public static <E extends Enum<E>> EnumSet<E> of(E e) { 152 EnumSet<E> set = EnumSet.noneOf(e.getDeclaringClass()); 153 set.add(e); 154 return set; 155 } 156 157 /** 158 * Creates a new enum set, containing only the specified elements. There are 159 * six overloadings of the method. They accept from one to five elements 160 * respectively. The sixth one receives an arbitrary number of elements, and 161 * runs slower than those that only receive a fixed number of elements. 162 * 163 * @param e1 164 * the initially contained element. 165 * @param e2 166 * another initially contained element. 167 * @return an enum set containing the specified elements. 168 * @throws NullPointerException 169 * if any of the specified elements is {@code null}. 170 */ 171 public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2) { 172 EnumSet<E> set = of(e1); 173 set.add(e2); 174 return set; 175 } 176 177 /** 178 * Creates a new enum set, containing only the specified elements. There are 179 * six overloadings of the method. They accept from one to five elements 180 * respectively. The sixth one receives an arbitrary number of elements, and 181 * runs slower than those that only receive a fixed number of elements. 182 * 183 * @param e1 184 * the initially contained element. 185 * @param e2 186 * another initially contained element. 187 * @param e3 188 * another initially contained element. 189 * @return an enum set containing the specified elements. 190 * @throws NullPointerException 191 * if any of the specified elements is {@code null}. 192 */ 193 public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3) { 194 EnumSet<E> set = of(e1, e2); 195 set.add(e3); 196 return set; 197 } 198 199 /** 200 * Creates a new enum set, containing only the specified elements. There are 201 * six overloadings of the method. They accept from one to five elements 202 * respectively. The sixth one receives an arbitrary number of elements, and 203 * runs slower than those that only receive a fixed number of elements. 204 * 205 * @param e1 206 * the initially contained element. 207 * @param e2 208 * another initially contained element. 209 * @param e3 210 * another initially contained element. 211 * @param e4 212 * another initially contained element. 213 * @return an enum set containing the specified elements. 214 * @throws NullPointerException 215 * if any of the specified elements is {@code null}. 216 */ 217 public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4) { 218 EnumSet<E> set = of(e1, e2, e3); 219 set.add(e4); 220 return set; 221 } 222 223 /** 224 * Creates a new enum set, containing only the specified elements. There are 225 * six overloadings of the method. They accept from one to five elements 226 * respectively. The sixth one receives an arbitrary number of elements, and 227 * runs slower than those that only receive a fixed number of elements. 228 * 229 * @param e1 230 * the initially contained element. 231 * @param e2 232 * another initially contained element. 233 * @param e3 234 * another initially contained element. 235 * @param e4 236 * another initially contained element. 237 * @param e5 238 * another initially contained element. 239 * @return an enum set containing the specified elements. 240 * @throws NullPointerException 241 * if any of the specified elements is {@code null}. 242 */ 243 public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4, E e5) { 244 EnumSet<E> set = of(e1, e2, e3, e4); 245 set.add(e5); 246 return set; 247 } 248 249 /** 250 * Creates a new enum set, containing only the specified elements. It can 251 * receive an arbitrary number of elements, and runs slower than those only 252 * receiving a fixed number of elements. 253 * 254 * @param start 255 * the first initially contained element. 256 * @param others 257 * the other initially contained elements. 258 * @return an enum set containing the specified elements. 259 * @throws NullPointerException 260 * if any of the specified elements is {@code null}. 261 */ 262 @SafeVarargs 263 public static <E extends Enum<E>> EnumSet<E> of(E start, E... others) { 264 EnumSet<E> set = of(start); 265 for (E e : others) { 266 set.add(e); 267 } 268 return set; 269 } 270 271 /** 272 * Creates an enum set containing all the elements within the range defined 273 * by {@code start} and {@code end} (inclusive). All the elements must be in 274 * order. 275 * 276 * @param start 277 * the element used to define the beginning of the range. 278 * @param end 279 * the element used to define the end of the range. 280 * @return an enum set with elements in the range from start to end. 281 * @throws NullPointerException 282 * if any one of {@code start} or {@code end} is {@code null}. 283 * @throws IllegalArgumentException 284 * if {@code start} is behind {@code end}. 285 */ 286 public static <E extends Enum<E>> EnumSet<E> range(E start, E end) { 287 if (start.compareTo(end) > 0) { 288 throw new IllegalArgumentException("start is behind end"); 289 } 290 EnumSet<E> set = EnumSet.noneOf(start.getDeclaringClass()); 291 set.setRange(start, end); 292 return set; 293 } 294 295 abstract void setRange(E start, E end); 296 297 /** 298 * Creates a new enum set with the same elements as those contained in this 299 * enum set. 300 * 301 * @return a new enum set with the same elements as those contained in this 302 * enum set. 303 */ 304 @SuppressWarnings("unchecked") 305 @Override 306 public EnumSet<E> clone() { 307 try { 308 return (EnumSet<E>) super.clone(); 309 } catch (CloneNotSupportedException e) { 310 throw new AssertionError(e); 311 } 312 } 313 314 boolean isValidType(Class<?> cls) { 315 return cls == elementClass || cls.getSuperclass() == elementClass; 316 } 317 318 private static class SerializationProxy<E extends Enum<E>> implements 319 Serializable { 320 321 private static final long serialVersionUID = 362491234563181265L; 322 323 private Class<E> elementType; 324 325 private E[] elements; 326 327 private Object readResolve() { 328 EnumSet<E> set = EnumSet.noneOf(elementType); 329 for (E e : elements) { 330 set.add(e); 331 } 332 return set; 333 } 334 } 335 336 @SuppressWarnings("unchecked") 337 Object writeReplace() { 338 SerializationProxy proxy = new SerializationProxy(); 339 proxy.elements = toArray(new Enum[0]); 340 proxy.elementType = elementClass; 341 return proxy; 342 } 343} 344