我想使用Joshua Bloch的Effective Java中描述的泛型類型安全容器模式,但想限制通過使用枚舉可以用作鍵的類。以下是Joshua書中的代碼。類型安全異構容器中的限制鍵
public class Favorites {
private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>();
public <T> void putFavorite(Class<T> type, T instance) {
if (type == null)
throw new NullPointerException("Type is null");
favorites.put(type, instance);
}
public <T> T getFavorite(Class<T> type) {
return type.cast(favorites.get(type));
}
}
我想編寫一個類似的類,但限制鍵說「Dog.class」和「Cat.class」。理想情況下,可接受的鍵將由枚舉來描述,而「RestrictedFavorites」類將把枚舉的成員作爲鍵。我不確定是否可以讓編譯器爲我完成所有這些事情(類型安全,枚舉限制,一般性),但如果有人有一個建議,我全都聽。以下是嘗試V1,它使用運行時檢查而不是編譯時間檢查,並不完全令人滿意。
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Attempt V1 At a "RestrictedFavorites" class
*/
public class RestrictedFavorites {
public static enum RestrictedKey {
STRING(String.class),
INTEGER(Integer.class);
private static Set<Class<?>> classes;
static {
classes = new HashSet<>();
for (RestrictedKey key: values()) {
classes.add(key.getKlass());
}
}
private final Class<?> klass;
RestrictedKey(Class<?> klass) {
this.klass = klass;
}
public Class<?> getKlass() {
return klass;
}
public static boolean isValidClassKey(Class<?> klass) {
return classes.contains(klass);
}
}
private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>();
//Ideally would use compile time checking
public <T> void putFavorite(RestrictedKey key, T instance) {
if (key == null) throw new NullPointerException("Type is null");
if (!key.getKlass().equals(instance.getClass())) {
throw new IllegalArgumentException(
"The type of the key must match the type of the instance");
}
favorites.put(key.getKlass(), instance);
}
//Ideally would take a RestrictedKey as an argument
public <T> T getFavorite(Class<T> key) {
if (!RestrictedKey.isValidClassKey(key)) {
throw new IllegalArgumentException(
"The key must be a member of RestrictedKeys");
}
return key.cast(favorites.get(key));
}
}
下面是一些單元測試來驗證我的課是做什麼大概我也想:
public class RestrictedFavoritesTest extends TestCase {
public void testPutFavorite() {
RestrictedFavorites myFavorites = new RestrictedFavorites();
myFavorites.putFavorite(RestrictedKey.INTEGER, 1);
myFavorites.putFavorite(RestrictedKey.STRING, "hey");
int expectedInt = myFavorites.getFavorite(Integer.class);
assertEquals(1, expectedInt);
String expectedString = myFavorites.getFavorite(String.class);
assertEquals("hey", expectedString);
}
public void testPutFavorite_wrongType() {
RestrictedFavorites myFavorites = new RestrictedFavorites();
try {
myFavorites.putFavorite(RestrictedKey.INTEGER, "hey");
fail();
} catch (IllegalArgumentException expected) {}
}
public void testPutFavorite_wrongClass() {
RestrictedFavorites myFavorites = new RestrictedFavorites();
try {
myFavorites.getFavorite(Boolean.class);
} catch (IllegalArgumentException expected) {}
}
}
使用'enum'作爲'Map'鍵和存儲在'enum'的屬性'Class'類型。 –
我試過這種方法。我已經爲我的問題添加了一個示例,但它不能編譯。如果我能弄清楚什麼,我會迭代併發布更好的版本。 –
在你的'getFavorite'中將返回類型轉換爲'T'。如果你想限制你的'Map'可以容納的實例沒有一些共同的父類,你將不得不依賴運行時檢查。你可以把這個方法放到你的'enum'中 - 它會稍微清理一下代碼。 –