1 7 8 package java.util; 9 import java.util.Map.Entry; 10 11 59 public class EnumMap<K extends Enum <K>, V> extends AbstractMap <K, V> 60 implements java.io.Serializable , Cloneable 61 { 62 67 private final Class <K> keyType; 68 69 72 private transient K[] keyUniverse; 73 74 79 private transient Object [] vals; 80 81 84 private transient int size = 0; 85 86 89 private static final Object NULL = new Object (); 90 91 private Object maskNull(Object value) { 92 return (value == null ? NULL : value); 93 } 94 95 private V unmaskNull(Object value) { 96 return (V) (value == NULL ? null : value); 97 } 98 99 private static Enum [] ZERO_LENGTH_ENUM_ARRAY = new Enum [0]; 100 101 107 public EnumMap(Class <K> keyType) { 108 this.keyType = keyType; 109 keyUniverse = keyType.getEnumConstants(); 110 vals = new Object [keyUniverse.length]; 111 } 112 113 120 public EnumMap(EnumMap <K, ? extends V> m) { 121 keyType = m.keyType; 122 keyUniverse = m.keyUniverse; 123 vals = (Object []) m.vals.clone(); 124 size = m.size; 125 } 126 127 139 public EnumMap(Map <K, ? extends V> m) { 140 if (m instanceof EnumMap ) { 141 EnumMap <K, ? extends V> em = (EnumMap <K, ? extends V>) m; 142 keyType = em.keyType; 143 keyUniverse = em.keyUniverse; 144 vals = (Object []) em.vals.clone(); 145 size = em.size; 146 } else { 147 if (m.isEmpty()) 148 throw new IllegalArgumentException ("Specified map is empty"); 149 keyType = m.keySet().iterator().next().getDeclaringClass(); 150 keyUniverse = keyType.getEnumConstants(); 151 vals = new Object [keyUniverse.length]; 152 putAll(m); 153 } 154 } 155 156 158 163 public int size() { 164 return size; 165 } 166 167 174 public boolean containsValue(Object value) { 175 value = maskNull(value); 176 177 for (Object val : vals) 178 if (value.equals(val)) 179 return true; 180 181 return false; 182 } 183 184 192 public boolean containsKey(Object key) { 193 return isValidKey(key) && vals[((Enum )key).ordinal()] != null; 194 } 195 196 private boolean containsMapping(Object key, Object value) { 197 return isValidKey(key) && 198 maskNull(value).equals(vals[((Enum )key).ordinal()]); 199 } 200 201 209 public V get(Object key) { 210 return (isValidKey(key) ? 211 unmaskNull(vals[((Enum )key).ordinal()]) : null); 212 } 213 214 216 230 public V put(K key, V value) { 231 typeCheck(key); 232 233 int index = ((Enum )key).ordinal(); 234 Object oldValue = vals[index]; 235 vals[index] = maskNull(value); 236 if (oldValue == null) 237 size++; 238 return unmaskNull(oldValue); 239 } 240 241 250 public V remove(Object key) { 251 if (!isValidKey(key)) 252 return null; 253 int index = ((Enum )key).ordinal(); 254 Object oldValue = vals[index]; 255 vals[index] = null; 256 if (oldValue != null) 257 size--; 258 return unmaskNull(oldValue); 259 } 260 261 private boolean removeMapping(Object key, Object value) { 262 if (!isValidKey(key)) 263 return false; 264 int index = ((Enum )key).ordinal(); 265 if (maskNull(value).equals(vals[index])) { 266 vals[index] = null; 267 size--; 268 return true; 269 } 270 return false; 271 } 272 273 277 private boolean isValidKey(Object key) { 278 if (key == null) 279 return false; 280 281 Class keyClass = key.getClass(); 283 return keyClass == keyType || keyClass.getSuperclass() == keyType; 284 } 285 286 288 297 public void putAll(Map <? extends K, ? extends V> m) { 298 if (m instanceof EnumMap ) { 299 EnumMap <? extends K, ? extends V> em = 300 (EnumMap <? extends K, ? extends V>)m; 301 if (em.keyType != keyType) { 302 if (em.isEmpty()) 303 return; 304 throw new ClassCastException (em.keyType + " != " + keyType); 305 } 306 307 for (int i = 0; i < keyUniverse.length; i++) { 308 Object emValue = em.vals[i]; 309 if (emValue != null) { 310 if (vals[i] == null) 311 size++; 312 vals[i] = emValue; 313 } 314 } 315 } else { 316 super.putAll(m); 317 } 318 } 319 320 323 public void clear() { 324 Arrays.fill(vals, null); 325 size = 0; 326 } 327 328 330 335 private transient Set <Map.Entry <K,V>> entrySet = null; 336 337 346 public Set <K> keySet() { 347 Set <K> ks = keySet; 348 if (ks != null) 349 return ks; 350 else 351 return keySet = new KeySet(); 352 } 353 354 private class KeySet extends AbstractSet <K> { 355 public Iterator <K> iterator() { 356 return new KeyIterator(); 357 } 358 public int size() { 359 return size; 360 } 361 public boolean contains(Object o) { 362 return containsKey(o); 363 } 364 public boolean remove(Object o) { 365 int oldSize = size; 366 EnumMap.this.remove(o); 367 return size != oldSize; 368 } 369 public void clear() { 370 EnumMap.this.clear(); 371 } 372 } 373 374 384 public Collection <V> values() { 385 Collection <V> vs = values; 386 if (vs != null) 387 return vs; 388 else 389 return values = new Values(); 390 } 391 392 private class Values extends AbstractCollection <V> { 393 public Iterator <V> iterator() { 394 return new ValueIterator(); 395 } 396 public int size() { 397 return size; 398 } 399 public boolean contains(Object o) { 400 return containsValue(o); 401 } 402 public boolean remove(Object o) { 403 o = maskNull(o); 404 405 for (int i = 0; i < vals.length; i++) { 406 if (o.equals(vals[i])) { 407 vals[i] = null; 408 size--; 409 return true; 410 } 411 } 412 return false; 413 } 414 public void clear() { 415 EnumMap.this.clear(); 416 } 417 } 418 419 428 public Set <Map.Entry <K,V>> entrySet() { 429 Set <Map.Entry <K,V>> es = entrySet; 430 if (es != null) 431 return es; 432 else 433 return entrySet = new EntrySet(); 434 } 435 436 private class EntrySet extends AbstractSet <Map.Entry <K,V>> { 437 public Iterator <Map.Entry <K,V>> iterator() { 438 return new EntryIterator(); 439 } 440 public boolean contains(Object o) { 441 if (!(o instanceof Map.Entry )) 442 return false; 443 Map.Entry entry = (Map.Entry )o; 444 return containsMapping(entry.getKey(), entry.getValue()); 445 } 446 public boolean remove(Object o) { 447 if (!(o instanceof Map.Entry )) 448 return false; 449 Map.Entry entry = (Map.Entry )o; 450 return removeMapping(entry.getKey(), entry.getValue()); 451 } 452 public int size() { 453 return size; 454 } 455 public void clear() { 456 EnumMap.this.clear(); 457 } 458 public Object [] toArray() { 459 return fillEntryArray(new Object [size]); 460 } 461 public <T> T[] toArray(T[] a) { 462 int size = size(); 463 if (a.length < size) 464 a = (T[])java.lang.reflect.Array 465 .newInstance(a.getClass().getComponentType(), size); 466 if (a.length > size) 467 a[size] = null; 468 return (T[]) fillEntryArray(a); 469 } 470 private Object [] fillEntryArray(Object [] a) { 471 int j = 0; 472 for (int i = 0; i < vals.length; i++) 473 if (vals[i] != null) 474 a[j++] = new AbstractMap.SimpleEntry <K,V>( 475 keyUniverse[i], unmaskNull(vals[i])); 476 return a; 477 } 478 } 479 480 private abstract class EnumMapIterator<T> implements Iterator <T> { 481 int index = 0; 483 484 int lastReturnedIndex = -1; 486 487 public boolean hasNext() { 488 while (index < vals.length && vals[index] == null) 489 index++; 490 return index != vals.length; 491 } 492 493 public void remove() { 494 checkLastReturnedIndex(); 495 496 if (vals[lastReturnedIndex] != null) { 497 vals[lastReturnedIndex] = null; 498 size--; 499 } 500 lastReturnedIndex = -1; 501 } 502 503 private void checkLastReturnedIndex() { 504 if (lastReturnedIndex < 0) 505 throw new IllegalStateException (); 506 } 507 } 508 509 private class KeyIterator extends EnumMapIterator<K> { 510 public K next() { 511 if (!hasNext()) 512 throw new NoSuchElementException (); 513 lastReturnedIndex = index++; 514 return keyUniverse[lastReturnedIndex]; 515 } 516 } 517 518 private class ValueIterator extends EnumMapIterator<V> { 519 public V next() { 520 if (!hasNext()) 521 throw new NoSuchElementException (); 522 lastReturnedIndex = index++; 523 return unmaskNull(vals[lastReturnedIndex]); 524 } 525 } 526 527 530 private class EntryIterator extends EnumMapIterator<Map.Entry <K,V>> 531 implements Map.Entry <K,V> 532 { 533 public Map.Entry <K,V> next() { 534 if (!hasNext()) 535 throw new NoSuchElementException (); 536 lastReturnedIndex = index++; 537 return this; 538 } 539 540 public K getKey() { 541 checkLastReturnedIndexForEntryUse(); 542 return keyUniverse[lastReturnedIndex]; 543 } 544 545 public V getValue() { 546 checkLastReturnedIndexForEntryUse(); 547 return unmaskNull(vals[lastReturnedIndex]); 548 } 549 550 public V setValue(V value) { 551 checkLastReturnedIndexForEntryUse(); 552 V oldValue = unmaskNull(vals[lastReturnedIndex]); 553 vals[lastReturnedIndex] = maskNull(value); 554 return oldValue; 555 } 556 557 public boolean equals(Object o) { 558 if (lastReturnedIndex < 0) 559 return o == this; 560 561 if (!(o instanceof Map.Entry )) 562 return false; 563 Map.Entry e = (Map.Entry )o; 564 V ourValue = unmaskNull(vals[lastReturnedIndex]); 565 Object hisValue = e.getValue(); 566 return e.getKey() == keyUniverse[lastReturnedIndex] && 567 (ourValue == hisValue || 568 (ourValue != null && ourValue.equals(hisValue))); 569 } 570 571 public int hashCode() { 572 if (lastReturnedIndex < 0) 573 return super.hashCode(); 574 575 Object value = vals[lastReturnedIndex]; 576 return keyUniverse[lastReturnedIndex].hashCode() 577 ^ (value == NULL ? 0 : value.hashCode()); 578 } 579 580 public String toString() { 581 if (lastReturnedIndex < 0) 582 return super.toString(); 583 584 return keyUniverse[lastReturnedIndex] + "=" 585 + unmaskNull(vals[lastReturnedIndex]); 586 } 587 588 private void checkLastReturnedIndexForEntryUse() { 589 if (lastReturnedIndex < 0) 590 throw new IllegalStateException ("Entry was removed"); 591 } 592 } 593 594 596 605 public boolean equals(Object o) { 606 if (!(o instanceof EnumMap )) 607 return super.equals(o); 608 609 EnumMap em = (EnumMap )o; 610 if (em.keyType != keyType) 611 return size == 0 && em.size == 0; 612 613 for (int i = 0; i < keyUniverse.length; i++) { 615 Object ourValue = vals[i]; 616 Object hisValue = em.vals[i]; 617 if (hisValue != ourValue && 618 (hisValue == null || !hisValue.equals(ourValue))) 619 return false; 620 } 621 return true; 622 } 623 624 630 public EnumMap <K, V> clone() { 631 EnumMap <K, V> result = null; 632 try { 633 result = (EnumMap <K, V>) super.clone(); 634 } catch(CloneNotSupportedException e) { 635 throw new AssertionError (); 636 } 637 result.vals = (Object []) result.vals.clone(); 638 return result; 639 } 640 641 644 private void typeCheck(K key) { 645 Class keyClass = key.getClass(); 646 if (keyClass != keyType && keyClass.getSuperclass() != keyType) 647 throw new ClassCastException (keyClass + " != " + keyType); 648 } 649 650 private static final long serialVersionUID = 458661240069192865L; 651 652 661 private void writeObject(java.io.ObjectOutputStream s) 662 throws java.io.IOException 663 { 664 s.defaultWriteObject(); 666 667 s.writeInt(size); 669 670 for (Map.Entry <K,V> e : entrySet()) { 672 s.writeObject(e.getKey()); 673 s.writeObject(e.getValue()); 674 } 675 } 676 677 681 private void readObject(java.io.ObjectInputStream s) 682 throws java.io.IOException , ClassNotFoundException 683 { 684 s.defaultReadObject(); 686 687 keyUniverse = keyType.getEnumConstants(); 688 vals = new Object [keyUniverse.length]; 689 690 int size = s.readInt(); 692 693 for (int i = 0; i < size; i++) { 695 K key = (K) s.readObject(); 696 V value = (V) s.readObject(); 697 put(key, value); 698 } 699 } 700 } 701 | Popular Tags |