我收到关于“return(T)值”未经检查的强制转换的警告;线。有更好的方法可以做到这一点,还是应该抑制警告?
class SomeClass<T>
{
/* ... other methods ... */
private Set<T> aSet;
public T filter(Object value)
{
if (this.aSet.contains(value))
return (T) value;
else
return null;
}
}
编辑:我坚持使用public T filter(Object value)
作为签名。
答案 0 :(得分:4)
如何使用泛型类型参数作为要过滤的参数类型。
class SomeClass
{
/* ... other methods ... */
private Set<T> aSet;
public T filter(T value)
{
if (this.aSet.contains(value))
return (T) value;
else
return null;
}
}
好的,既然你坚持使用object
签名,那么你没有其他任何机会,但是禁用/忽略警告。 Java Generics在底层类型系统支持它们的意义上不是“真正的泛型”。实际上,它们只是一个编译器,因为它们基于Type Erasure。性能损失和可能不安全的转换是维护与旧版JVM的二进制兼容性的代价。
你可以将它与具有真正泛型的.NET CLR进行对比,我写了blog post比较最近的两种方法,如果我上面提到的任何内容让你感到困惑,你也可以参考这两种方法。 / p>
答案 1 :(得分:3)
在这种情况下,您可以取消警告并发表评论保存的原因:
if (this.aSet.contains(value)) {
// this following cast from Object to T is save, because ...
@SuppressWarnings("unchecked") T result = (T) value;
return result;
} else
return null;
有一种替代方案,但这需要,类或方法'知道'它的参数化类型。然后我们可以在没有警告的情况下施放(但也应该发表评论)。我展示了一个解决方案,我们引入/更改构造函数以将“泛型”信息存储为字段:
public class SomeClass<T> {
private Set<T> aSet;
private Class<T> genericType;
public SomeClass(Class<T> genericType) {
this.genericType = genericType;
}
public T filter(Object value)
{
if (this.aSet.contains(value))
// this following cast from Object to T is save, because ...
return genericType.cast(value);
else
return null;
}
}
答案 2 :(得分:2)
有可能:)
public T filter(Object value)
{
if (this.aSet.contains(value)) {
Set<T> tmp = new TreeSet<T>(aSet);
tmp.retainAll(Collections.singleton(value));
return tmp.iterator().next();
}
return null;
}
但这显然比做演员更丑陋。
答案 3 :(得分:2)
也许你可以替换:
private Set<T> aSet;
带
private final Map<T,T> aSet;
Set
可能会以Map
的形式实现。
答案 4 :(得分:2)
阐述Tom Hawtin的回答,您可以选择使用Map<T,T>
来解决投射问题。如果您使用HashSet<T>
进行aSet
的实施,HashSet
无论如何都会在幕后使用HashMap<T,HashSet<T>>
(它使用对自身的引用作为值 - 不确定是否除了选择之外,还有一个原因 - 将集合的“值”作为键)并通过重新解释Map
函数的返回值来执行大部分操作。
因此,如果您愿意,可以执行此操作(并且我没有立即明白为什么它的性能会比HashSet
更低):
class SomeClass<T>
{
/* ... other methods ... */
private Map<T,T> aSet;
public T filter(Object value)
{
// Will return the properly-typed object if it's in
// the "set" otherwise will return null
return aSet.get(value);
}
}
答案 5 :(得分:1)
这是你的意思吗?
public class SomeClass<T>
{
private Set<T> aSet;
public T filter(Object value)
{
return (aSet.contains(value) ? (T) value : null);
}
}
答案 6 :(得分:0)
这样做的问题在于它是等待发生的ClassCastException。如果你的对象不属于T
类,但是equals
对象是你的一个元素,那么当你尝试将它强制转换为T时,它将会失败。你需要的是获取集合中包含的实际值,你知道它是T类型。不幸的是,Set没有get方法,所以你需要暂时将它转换为具有类似的方法的集合。列表。
您可以尝试这样做:
private Set<T> aSet;
public T filter(Object value) {
List<T> list = new ArrayList<T>(aSet);
int index = list.indexOf(value);
if (index == -1) {
return null;
}
T setValue = list.get(index);
return setValue;
}
这可能会降低性能,但它提供了更多的类型安全性。