[英]Type safe merging of Map with multiple types for its value; `incompatible types java.lang.Object cannot be converted to capture#1 of ?`
I have a container class which has a Map
which is carrying multiple types for its value.我有一个容器类,它有一个
Map
,它携带多种类型的值。 To make it type safe from the external point of view, the key itself has a generic type, indicating what the type of the value will be.为了从外部的角度来看是类型安全的,键本身有一个泛型类型,指示值的类型。
The key provides some basic facilities to look up items and merge their values.键提供了一些基本的工具来查找项目并合并它们的值。 (There might be different merging rules for the type of value that is found).
(找到的值类型可能有不同的合并规则)。
public abstract class Key<T> {
@SuppressWarnings("unchecked")
T get(Map<Key<?>, Object> data) {
return (T) data.get(this);
}
/**
* This must be provided by the implementation.
*
* @param old the old value
* @param new the new value
* @returns the merged value
*/
abstract T merge(T old, T new);
}
The Container
class then looks like this. Container
类看起来像这样。
public class Container {
private final Map<Key<?>, Object> data = new HashMap<>();
public <T> Optional<T> get(Key<T> key) {
return Optional.ofNullable(key.get(data));
}
public <T> Container set(Key<T> key, T value) {
data.put(key, value);
return this;
}
@SuppressWarnings("unchecked")
public <T> Container merge(Key<T> key, T newValue) {
data.compute(key, (k, oldValue) -> key.merge((T) oldValue, newValue));
return this;
}
public Container mergeAll(Container that) {
//this does not compile: incompatible types java.lang.Object cannot be converted to capture#1 of ?
that.data.forEach((key, value) -> this.data.merge(key, value, key::merge));
return this;
}
}
All of this works fine, apart from the last mergeAll
method.除了最后一个
mergeAll
方法之外,所有这些都可以正常工作。 It is looking at all the keys of the that
container and merge their values with those of the this
container.它正在查看
that
容器的所有键并将它们的值与this
容器的值合并。
However the key::merge
doesn't compile with an error incompatible types java.lang.Object cannot be converted to capture#1 of ?
但是,
key::merge
无法编译并出现错误incompatible types java.lang.Object cannot be converted to capture#1 of ?
. .
In the single merge()
method I got around it with a type cast to (T)
.在单个
merge()
方法中,我通过将类型转换为(T)
来解决它。 But in this case I don't have a generic type, it is ?
但在这种情况下,我没有泛型类型,它是
?
, but I cannot do something like: (key, oldValue) -> key.merge((?) oldValue, (?) value)
because you cannot cast to (?)
. ,但我不能做这样的事情:
(key, oldValue) -> key.merge((?) oldValue, (?) value)
因为你不能转换为(?)
。
Is there a way around this?有没有解决的办法? Or a better pattern to implement what I am trying to achieve?
或者更好的模式来实现我想要实现的目标?
You should be able to fix this by writing:您应该能够通过编写以下内容来解决此问题:
public Container mergeAll(Container that) {
that.data.forEach((key, value) -> this.data.merge(key, value, ((Key<Object>) key)::merge));
return this;
}
In your example, key
has an unbounded wildcard type Key<?>
, so methods accepting generic parameters cannot accept anything but null
.在您的示例中,
key
具有无界通配符类型Key<?>
,因此接受泛型参数的方法只能接受null
。 As the values passed to merge
are of type Object
, you can cast your key
to Key<Object>
.由于传递给
merge
的值属于Object
类型,因此您可以将key
为Key<Object>
。
Another solution might probably be to change Key<?>
to Key<Object>
if this is applicable in your situation.如果这适用于您的情况,另一种解决方案可能是将
Key<?>
更改为Key<Object>
。
I don't think it'll get any more type safe than this, because the map Map<Key<?>, Object> data
has no hint for the compiler that the class of the value is actually supposed to be the generic type of the key.我认为它不会比这更安全,因为映射
Map<Key<?>, Object> data
没有提示编译器该值的类实际上应该是钥匙。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.