我还有一个问题是关于https://gafter.blogspot.com/2006/12/super-type-tokens.html 显示了类型安全的异构容器模式。
public class FavoritesClass {
private final Map<Class<?>, Object> favorites = new HashMap<>();
public <T> void setFavorite(Class<T> klass, T thing) {
favorites.put(klass, thing);
}
public <T> T getFavorite(Class<T> klass) {
return klass.cast(favorites.get(klass));
}
public static void main(String[] args) {
FavoritesClass f = new FavoritesClass();
f.setFavorite(String.class, "Java");
f.setFavorite(Integer.class, 0xcafebabe);
String s = f.getFavorite(String.class);
int i = f.getFavorite(Integer.class);
System.out.println(s);
System.out.println(i);
// you simply can't make a type token for a generic type because of erasure
f.setFavorite(List<String>.class, Collections.emptyList());
}
}
这个例子展示了如何将各种对象保存在
favorites Map
以类型安全的方式使用类型标记作为 Map
钥匙。
但由于擦除的原因,不可能使用泛型类型。
我尝试使用超类型标记方法扩展示例( TypeReference
类)在文章中建议,但我不能使其类型安全。
/**
* References a generic type.
*
* @author crazybob@google.com (Bob Lee)
*/
public abstract class TypeReference<T> {
private final Type type;
private volatile Constructor<?> constructor;
protected TypeReference() {
Type superclass = getClass().getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0];
}
/**
* Instantiates a new instance of {@code T} using the default, no-arg
* constructor.
*/
@SuppressWarnings("unchecked")
public T newInstance()
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
if (constructor == null) {
Class<?> rawType = type instanceof Class<?>
? (Class<?>) type
: (Class<?>) ((ParameterizedType) type).getRawType();
constructor = rawType.getConstructor();
}
return (T) constructor.newInstance();
}
/**
* Gets the referenced type.
*/
public Type getType() {
return this.type;
}
}
我的扩展示例:
public class FavoritesTypeReference {
private final Map<TypeReference<?>, Object> favorites = new HashMap<>();
public <T> void setFavorite(TypeReference<T> typeReference, T thing) {
favorites.put(typeReference, thing);
}
public <T> void setFavorite(Class<T> klass, T thing) {
TypeReference<T> typeReference = new TypeReference<T>() {
};
favorites.put(typeReference, thing);
}
public <T> T getFavorite(Class<T> klass) {
TypeReference<T> typeReference = new TypeReference<T>() {
};
return klass.cast(favorites.get(typeReference));
}
public <T> T getFavorite(TypeReference<T> typeReference) {
Class<T> klass = (Class<T>) typeReference.getType();
return klass.cast(favorites.get(typeReference));
}
public static void main(String[] args) {
FavoritesTypeReference f = new FavoritesTypeReference();
f.setFavorite(String.class, "Java");
f.setFavorite(Integer.class, 0xcafebabe);
String s = f.getFavorite(String.class);
int i = f.getFavorite(Integer.class);
System.out.println(s);
System.out.println(i);
// erasure kicks in here, so I can't do it
// you simply can't make a type token for a generic type.
// f.setFavorite(List<String>.class, Collections.emptyList());
f.setFavorite(new TypeReference<List<String>>() {
}, Arrays.asList("Java", "Kotlin"));
List<String> favorite = f.getFavorite(new TypeReference<List<String>>() {
});
System.out.println(favorite);
}
}
如你所见,我得做些什么 Class<T> klass = (Class<T>) typeReference.getType();
在 getFavorite
方法。
有什么方法可以避免这样做吗?
或者我的解决方案是唯一的出路?
1条答案
按热度按时间vsikbqxv1#
经过反复试验,我意识到
Map<Class<?>, Object> favorites
或者Map<TypeReference<?>, Object> favorites
.最后一个例子是: