我可以使用包含A或列表<a>?</a>的类型安全地图吗?

时间:2011-07-13 16:49:32

标签: java generics

我需要一个包含

的Map容器
  

Item Object

  

List<Item> Object

作为它的价值,而且我可以在没有施放的情况下得到它,是否可能?

6 个答案:

答案 0 :(得分:3)

简短回答:不。

Java中不存在

Union types。为了获得编译时类型检查,你可以做的最接近的事情是创建一些包含 AList<A>的自定义包装类的列表,如下:

public class UnionListWrapper<A> {
    private final A item;
    private final List<A> list;

    public UnionListWrapper(A value) {
        item = value;
        list = null;
    }

    public UnionListWrapper(List<A> value) {
        item = null;
        list = value;
    }

    public Object getValue() {
        if (item != null) return item;
        else return list;
    }
}

至少你不能创建这个类的实例,这些实例不是AList<A>,但是将值重新输出将会仍然必须只是Object,与关联铸造。这可能会非常笨拙,总的来说可能不值得。

在实践中,我可能只有一个List<Object>,并且对于接受哪些数据类型非常谨慎。问题是即使是运行时检查(次优)也是不可能的,因为Java的通用擦除意味着你不能在运行时进行instanceof A检查(在通用参数上加倍) List)。

答案 1 :(得分:3)

不,你不能以类型安全的方式做到这一点。

从设计的角度来看,我建议仅使用List<Item>作为值。如果其中一些是单元素列表,那就没问题;如果以相同的方式处理所有值,您的代码可能会更加清晰。

事实上,我很好奇你打算如何使用带有元素和元素列表的地图。您是否知道某个给定密钥的先验类型?

答案 2 :(得分:2)

听起来你想要一个MultiMap - 有一个Apache implementation和一个Google implementation

答案 3 :(得分:1)

可能是您正在寻找的类型安全的异构容器模式

http://books.google.com/books?id=ka2VUBqHiWkC&pg=PA142&lpg=PA142&dq=type+safe+heterogeneous+container+pattern&source=bl&ots=yYDfNltZS3&sig=giH1d_rIQ-MumOnrMmiT4OgtM7E&hl=en&ei=880dTqHcJYSyhAeVhqS3Bw&sa=X&oi=book_result&ct=result&resnum=5&ved=0CDUQ6AEwBA#v=onepage&q=type%20safe%20heterogeneous%20container%20pattern&f=false

解决下面评论中提到的优点:重新键入擦除 - 使用超类型令牌。取自http://gafter.blogspot.com/2007/05/limitation-of-super-type-tokens.html,突出了该方法的问题。

import java.lang.reflect.*;

public abstract class TypeRef<T> {
    private final Type type;
    protected TypeRef() {
        ParameterizedType superclass = (ParameterizedType)
            getClass().getGenericSuperclass();
        type = superclass.getActualTypeArguments()[0];
    }
    @Override public boolean equals (Object o) {
        return o instanceof TypeRef &&
            ((TypeRef)o).type.equals(type);
    }
    @Override public int hashCode() {
        return type.hashCode();
    }
}

public class Favorites2 {
    private Map<TypeRef<?>, Object> favorites =
        new HashMap< TypeRef<?> , Object>();
    public <T> void setFavorite(TypeRef<T> type, T thing) {
        favorites.put(type, thing);
    }
    @SuppressWarning("unchecked")
    public <T> T getFavorite(TypeRef<T> type) {
        return (T) favorites.get(type);
    }
    public static void main(String[] args) {
        Favorites2 f = new Favorites2();
        List<String> stooges = Arrays.asList(
            "Larry", "Moe", "Curly");
        f.setFavorite(new TypeRef<List<String>>(){}, stooges);
        List<String> ls = f.getFavorite(
            new TypeRef<List<String>>(){});
    }
} 

答案 4 :(得分:0)

不是没有编写包含单个A或List的包装类(WrapsA),并且使列表成为List

答案 5 :(得分:0)

Functional Java提供了一个名为Either<A, B>的不相交联合数据类型,因此您可以定义Map<Key, Either<Item, List<Item>>>