001 /* 002 * Copyright (C) 2007 Google Inc. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package com.google.common.collect; 018 019 import java.io.IOException; 020 import java.io.ObjectInputStream; 021 import java.io.ObjectOutputStream; 022 import java.util.EnumMap; 023 import java.util.HashMap; 024 import java.util.Map; 025 026 import javax.annotation.Nullable; 027 028 /** 029 * A {@code BiMap} backed by an {@code EnumMap} instance for keys-to-values, and 030 * a {@code HashMap} instance for values-to-keys. Null keys are not permitted, 031 * but null values are. An {@code EnumHashBiMap} and its inverse are both 032 * serializable. 033 * 034 * @author Mike Bostock 035 * @since 2 (imported from Google Collections Library) 036 */ 037 public final class EnumHashBiMap<K extends Enum<K>, V> 038 extends AbstractBiMap<K, V> { 039 private transient Class<K> keyType; 040 041 /** 042 * Returns a new, empty {@code EnumHashBiMap} using the specified key type. 043 * 044 * @param keyType the key type 045 */ 046 public static <K extends Enum<K>, V> EnumHashBiMap<K, V> 047 create(Class<K> keyType) { 048 return new EnumHashBiMap<K, V>(keyType); 049 } 050 051 /** 052 * Constructs a new bimap with the same mappings as the specified map. If the 053 * specified map is an {@code EnumHashBiMap} or an {@link EnumBiMap}, the new 054 * bimap has the same key type as the input bimap. Otherwise, the specified 055 * map must contain at least one mapping, in order to determine the key type. 056 * 057 * @param map the map whose mappings are to be placed in this map 058 * @throws IllegalArgumentException if map is not an {@code EnumBiMap} or an 059 * {@code EnumHashBiMap} instance and contains no mappings 060 */ 061 public static <K extends Enum<K>, V> EnumHashBiMap<K, V> 062 create(Map<K, ? extends V> map) { 063 EnumHashBiMap<K, V> bimap = create(EnumBiMap.inferKeyType(map)); 064 bimap.putAll(map); 065 return bimap; 066 } 067 068 private EnumHashBiMap(Class<K> keyType) { 069 super(new EnumMap<K, V>(keyType), Maps.<V, K>newHashMapWithExpectedSize( 070 keyType.getEnumConstants().length)); 071 this.keyType = keyType; 072 } 073 074 // Overriding these two methods to show that values may be null (but not keys) 075 076 @Override public V put(K key, @Nullable V value) { 077 return super.put(key, value); 078 } 079 080 @Override public V forcePut(K key, @Nullable V value) { 081 return super.forcePut(key, value); 082 } 083 084 /** Returns the associated key type. */ 085 public Class<K> keyType() { 086 return keyType; 087 } 088 089 /** 090 * @serialData the key class, number of entries, first key, first value, 091 * second key, second value, and so on. 092 */ 093 private void writeObject(ObjectOutputStream stream) throws IOException { 094 stream.defaultWriteObject(); 095 stream.writeObject(keyType); 096 Serialization.writeMap(this, stream); 097 } 098 099 @SuppressWarnings("unchecked") // reading field populated by writeObject 100 private void readObject(ObjectInputStream stream) 101 throws IOException, ClassNotFoundException { 102 stream.defaultReadObject(); 103 keyType = (Class<K>) stream.readObject(); 104 setDelegates(new EnumMap<K, V>(keyType), 105 new HashMap<V, K>(keyType.getEnumConstants().length * 3 / 2)); 106 Serialization.populateMap(this, stream); 107 } 108 109 private static final long serialVersionUID = 0; 110 }