我是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
希望类型为lhs
,Class<?>
类型为rhs
{1}}。有没有办法以我想要的方式做到这一点?或者,当我将对象的类型放入通配符对象的容器(本例中为Map)时,它的类型总是会丢失吗?
答案 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();