英文:
Class implementing an interface is not accepted for generics wildcard
问题
我想要一个以类类型作为键的映射,以避免在访问值时进行强制转换。
更新
以下是您可以复制粘贴到IDEA中并进行重现的实际代码。
interface MyInterface {
}
class SomeConcreteClass implements MyInterface{
}
private Map<Class<?>, ? extends MyInterface> map = newMap();
private Map<Class<?>, ? extends MyInterface> newMap() {
Map<Class<?>, ? extends MyInterface> map = new HashMap<>();
map.put(SomeConcreteClass.class, new SomeConcreteClass());
return map;
}
private void accessMap() {
SomeConcreteClass clazz = (SomeConcreteClass) map.get(SomeConcreteClass.class); // <== 我想避免在这里进行强制转换
}
问题:这段代码无法编译。我在以下这行:
map.put(SomeConcreteClass.class, new SomeConcreteClass());
出现了错误:
错误的第二个参数类型。找到:'SomeConcreteClass',需要:'?extends MyInterface'
我在这里做错了什么?SomeConcreteClass
应该被接受,因为它实现了接口。
英文:
I would like to have a map with the class type as a key in order to avoid casting when accessing the value.
Update
The following is actual code you can copy/paste in an IDEA and reproduce it.
interface MyInterface {
}
class SomeConcreteClass implements MyInterface{
}
private Map<Class<?>, ? extends MyInterface> map = newMap();
private Map<Class<?>, ? extends MyInterface> newMap() {
Map<Class<?>, ? extends MyInterface> map = new HashMap<>();
map.put(SomeConcreteClass.class, new SomeConcreteClass());
return map;
}
private void accessMap() {
SomeConcreteClass clazz = (SomeConcreteClass) map.get(SomeConcreteClass.class); <== I want to avoid cast here
}
Problem: This does not compile. I get in this line:
map.put(SomeConcreteClass.class, new SomeConcreteClass());
the error:
> Wrong 2nd argument type. Found: 'SomeConcreteClass required '? extends
> MyInterface`
What am I doing wrong here? SomeConcreteClass
should be accepted as it implements the interface
答案1
得分: 1
这可以大大简化:
Map<String, ? extends CharSequence> map = new HashMap<>();
map.put("", ""); // <-- 将无法编译
List<? extends CharSequence> l = new ArrayList<>();
l.add(""); // <-- 将无法编译
这背后的原则被称为 PECS
(非常著名)。为什么不允许这样做的解释有点冗长,但主要在这里有详细解释。虽然不明显,但如果允许这样做,可能会在其他地方引起问题,我链接的答案解释了这一点。
你可以通过所谓的“类型安全的异构容器”来实现你想要的效果:
static class TypeSafeValue {
private MyInterface t;
TypeSafeValue() {
}
public <T> TypeSafeValue setValue(MyInterface t) {
this.t = t;
return this;
}
public <T> T getValue(Class<T> clazz) {
return clazz.cast(t);
}
}
使用方法如下:
private Map<Class<?>, TypeSafeValue> newMap() {
Map<Class<?>, TypeSafeValue> map = new HashMap<>();
map.put(SomeConcreteClass.class, new TypeSafeValue().setValue(new SomeConcreteClass()));
return map;
}
private void accessMap() {
SomeConcreteClass clazz = map.get(SomeConcreteClass.class).getValue(SomeConcreteClass.class);
}
英文:
This can be simplified, a lot:
Map<String, ? extends CharSequence> map = new HashMap<>();
map.put("", ""); // <-- will not compile
List<? extends CharSequence> l = new ArrayList<>();
l.add(""); // <-- will not compile
The principle behind this is called PECS
(very famous). Why this is not allowed is a bit verbose to read, but mainly explained here. Though not obvious, if that would be allowed - it might cause problems in other places, the answer I linked explains that.
You can achieve what you want with a so-called typesafe heterogeneous container
:
static class TypeSafeValue {
private MyInterface t;
TypeSafeValue() {
}
public <T> TypeSafeValue setValue(MyInterface t) {
this.t = t;
return this;
}
public <T> T getValue(Class<T> clazz) {
return clazz.cast(t);
}
}
And usage would be:
private Map<Class<?>, TypeSafeValue> newMap() {
Map<Class<?>, TypeSafeValue> map = new HashMap<>();
map.put(SomeConcreteClass.class, new TypeSafeValue().setValue(new SomeConcreteClass()));
return map;
}
private void accessMap() {
SomeConcreteClass clazz = map.get(SomeConcreteClass.class).getValue(SomeConcreteClass.class);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论