Java 我是否可以拥有包含或列表的类型安全映射<;A>;?

Java 我是否可以拥有包含或列表的类型安全映射<;A>;?,java,generics,Java,Generics,我需要一个包含 项目对象 或 列出对象 作为它的价值,我可以不施法就把它拿出来,这可能吗?简短回答:不可能 不存在于Java中。为了进行编译时类型检查,您可以做的最接近的事情是创建某个自定义包装器类的列表,该类包含A或list,如下所示: public class UnionListWrapper<A> { private final A item; private final List<A> list; public UnionListWrap

我需要一个包含

项目对象

列出对象

作为它的价值,我可以不施法就把它拿出来,这可能吗?

简短回答:不可能

不存在于Java中。为了进行编译时类型检查,您可以做的最接近的事情是创建某个自定义包装器类的列表,该类包含
A
list
,如下所示:

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;
    }
}
公共类UnionListWrapper{
私人决赛项目;
私人最终名单;
公共UnionListWrapper(一个值){
项目=价值;
列表=空;
}
公共UnionListWrapper(列表值){
item=null;
列表=值;
}
公共对象getValue(){
如果(项目!=null)返回项目;
其他返回列表;
}
}
至少您无法创建此类的实例,这些实例既不是
A
也不是
列表
,但要将值恢复到
Object
,还需要关联强制转换。这可能会变得相当笨拙,总的来说,这可能不值得


在实践中,我可能只会有一个
列表
,其中包含一些注释,说明在接受哪些数据类型时要非常小心。问题是,即使运行时检查(次优)也不可能,因为Java的泛型擦除意味着您无法在运行时执行检查的
实例(对
列表
的泛型参数加倍如此)。

必须编写一个包含单个A或列表的包装类(WrapsA),让您的列表成为列表听起来像是您想要一个多重映射——有一个和一个可能是类型安全的异构容器模式

针对下面评论中提出的优点,使用超级类型标记重新键入擦除。摘自,突出了该方法的一个问题

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>>(){});
    }
} 
import java.lang.reflect.*;
公共抽象类TypeRef{
私有最终类型;
受保护的TypeRef(){
ParameteredType超类=(ParameteredType)
getClass().getGenericSuperclass();
类型=超类。getActualTypeArguments()[0];
}
@重写公共布尔等于(对象o){
返回TypeRef的0实例&&
((TypeRef)o).type.equals(type);
}
@重写公共int hashCode(){
返回类型:hashCode();
}
}
公共类偏好2{
私有映射,对象>();
public void setFavorite(TypeRef类型,T thing){
收藏。放置(类型、物品);
}
@抑制警告(“未选中”)
公共T getFavorite(TypeRef类型){
返回(T)收藏夹。获取(类型);
}
公共静态void main(字符串[]args){
Favorites2 f=新的Favorites2();
List stooges=Arrays.asList(
“拉里”、“莫”、“卷发”);
f、 setFavorite(新的TypeRef(){},stooges);
列表ls=f.getFavorite(
新的TypeRef(){});
}
} 

不,您不能以类型安全的方式执行此操作

从设计的角度来看,我建议只使用
List
作为值。如果其中有些是单元素列表,那就好了;如果以相同的方式处理所有值,代码可能会更干净


事实上,我很好奇你打算如何使用一个包含元素和元素列表的映射。您知道对于给定的键应该使用哪种类型吗?

提供了一种称为的不相交的联合数据类型,因此您可以定义一个
映射

如何获得一个
实例(已擦除的)类型
用作键?此外,类型安全的异构容器只允许每个类型有一个值。您可以使用超级类型令牌进行类型擦除。如果需要存储同一类型的多个值,您应该能够通过包装异构映射器类型标记来满足此要求。但是,多映射器类型标记并不是真正的类型安全的:多映射如何处理不同类型值的类型安全问题?似乎这两种实现都需要向下转换
对象
值。@erickson——好吧,Google的实现至少是通过键和值类型以及类型安全来参数化的。是的,但是您可以为参数指定什么?您仍然有
Multimap
来容纳
列表
作为值,因此问题不会改变。我在问题陈述中看不到任何东西支持这样的观点,即对于给定的密钥,
列表
都将被存储。@erickson不,您不存储列表,multimap会在封面下为您存储列表;你只按键类型和值类型进行参数化,“不施法就把它拿出来”的部分让我抓狂。你希望如何使用那张地图?类似于
A=map.get(“key1”);List=map.get(“key2”)
永远不可能,因为
get
方法不能有两种不同的返回类型。