我是通配符的新手,对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;
}

}

我在地图中存储了这些UserVariable的集合。我在定义Map时使用了通配符,以便可以将所有类型的UserVariable都存储在一个Map中。这里的想法是我的软件的用户正在创建变量并给它们命名,并且该软件可以使用变量名作为键在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>getType()方法应返回Class<T>。同样,在构造每个type时存储每个UserVariableUserVariable。但是,最后一次赋值给出以下错误:

类型不匹配:无法从Class<capture#1-of ?>转换为Class<T>
也许是因为Map是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对象。稍后,我在该对象上调用evaluate,传入当前变量值的Map,它将当前变量值(从Map中获取)与构造时传入的比较值进行比较,并返回结果。

但是,我不确定对compareTo的调用是否会起作用,因为lhs希望为Class<?>类型,而rhs希望为Class<T>类型。有没有办法按照我的意图去做?还是当我将其放入通配符对象的容器(在这种情况下为Map)时,对象的类型是否总是丢失?

最佳答案

泛型由编译器严格检查。因此,只要您维护与同一类型的其他实例相关的每个与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();

10-06 07:27