Java:难以从通配符泛型分配泛型

时间:2016-10-12 20:15:28

标签: java generics collections wildcard

我是Java的新手,并且对Java中的泛型相对缺乏经验,我遇到了分配它们的问题。

我有一个名为UserVariable<T>的自定义泛型类。每个UserVariable都知道关于它自身的两件事:它的类型和它的值,这两者都是在它构造时所期望的。准系统定义如下:

class UserVariable<T extends Comparable<T>> implements Comparable<UserVariable<T>>
{

private T value;
private final transient Class<T> type;

public UserVariable(T value, Class<T> type)
{
    this.value = value;
    this.type = type;
}

public T getValue()
{
    return value;
}

public Class<T> getType()
{
    return type;
}

}

我有一组存储在Map中的UserVariables。我在定义Map时使用了通配符,这样我就可以在一个Map中存储各种类型的UserVariables。这里的想法是我的软件用户正在创建变量并给它们命名,软件可以使用变量名作为关键字在Map中存储/查找变量:

class VarsMap {

private ObservableMap<String, UserVariable<?>> userVars = FXCollections.observableHashMap();

public void setVariable(String name, UserVariable<?> variable)
{
    userVars.put(name, variable);
}

public UserVariable<?> getVariable(String name)
{
    return userVars.get(name);
}

}

后来,我有一个类试图检索其中一个变量并存储其类型。我在最后一次任务中遇到了麻烦...

class SimpleComparison<T extends Comparable<T>> {

private StringProperty variableName = new SimpleStringProperty("");
private T comparisonValue;
private transient Class<T> myVarType;

public SimpleComparison(String variableName, T value, VarsMap theVars)
{
    this.myVarType = theVars.getVariable(variableName).getType();  //error here
}

}

this.myVarType定义为Class<T>UserVariable<T>&#39; getType()方法应返回Class<T>。此外,每个type的{​​{1}}都会在每个UserVariable构建时存储。但是,最后一次分配会出现以下错误:

类型不匹配:无法从UserVariable转换为Class<capture#1-of ?>

也许这是因为地图是Class<T>的地图?有谁知道我在这里做错了什么?谢谢你的帮助!

编辑:最后我要做的是UserVariable<?>中有一个名为SimpleComparison的方法来执行此操作:

evaluate

也就是说,我使用变量名和要比较的值构造一个public int evaluate(VarsMap theVars) { UserVariable<T> lhs = theVars.getVariable(variableName); UserVariable<T> rhs = new UserVariable<T>(comparisonValue, myVarType); return lhs.compareTo(rhs); } 对象。稍后我在该对象上调用SimpleComparison,传入当前变量值的Map,并将变量的当前值(取自Map)与构造时传递的比较值进行比较,并返回结果。

但是,我不确定对evaluate的调用是否有效,因为compareTo希望类型为lhsClass<?>类型为rhs {1}}。有没有办法以我想要的方式做到这一点?或者,当我将对象的类型放入通配符对象的容器(本例中为Map)时,它的类型总是会丢失吗?

2 个答案:

答案 0 :(得分:2)

问题是您的地图包含具有不同类型参数的值(您可以存储Class<Integer>Class<String>等),当您从地图中获取值时,您不知道是什么值包含的类型参数和编译器引发错误,因为您不能使用类型参数不同于Class<T>来转换为T值(但您可以通过{{显式转换为Class<T> 1}}编译器警告不安全的演员表。)

答案 1 :(得分:1)

编译器严格检查泛型。因此,只要您将每个通用实例化相关的onyl维护到相同类型的其他实例,一切都很好:

MyGeneric<String> s1=...
MyOtherGeneric<String> o1=...
s1.doSomething(o1);

当您尝试混合类型时会出现问题:

MyGeneric<String> s1=...
MyOtherGeneric<Double> o1=...
s1.doSomething(o1);    // Error

好的,这很明显。在您的情况下,问题是类似的:您尝试收集几个通用实例化无关紧要 - 它们基于类型 - 它们基于非通用抽象VarsMap

因此,当您尝试将非泛型抽象VarsMap中包含的对象与通用对象Class<T>混合时,编译器如何确定其类型是否匹配?然后出现编译器错误。

我看到的最简单的解决方案:由于您已经按名称匹配UserVariable个对象,并且我认为每个变量的类型始终相同,您可以依赖此程序生成的检查并假设它们的类型将匹配:只需将方法范围的参数添加到方法getVariable和简单的强制转换:

public <T extends Comparable<T>> UserVariable<T> getVariable(String name)
{
    return (UserVariable<T>)this.userVars.get(name);
}

...并且还可以在任何地方添加适当的类型参数替换:

this.myVarType=theVars.<T> getVariable(variableName).getType();