如何使用 Java 泛型解决这种情况?
How can I resolve this situation with Java Generics?
我有以下 class 层次结构:
public abstract class MyParentObject {}
public abstract class MyObject<T> extends MyParentObject {}
public abstract class MyParentContainer<T extends MyParentObject> {
private Class<T> valueType;
protected MyParentContainer(Class<T> valueType) {
this.valueType = valueType;
}
}
public abstract class MyObjectContainer<T extends MyObject<?>> extends MyParentContainer<T> {
protected MyObjectContainer(Class<T> valueType) {
super(valueType);
}
}
目前为止一切正常。 MyObject
有几个子classes 和几个容器classes 有一些子classes 作为valueType
,例如
public class IntObject extends MyObject<Integer> {}
public class IntContainer extends MyObjectContainer<IntObject> {
public IntContainer() {
super(IntObject.class);
}
}
现在我需要实现一个容器,尽管它与 MyObject
.
的一组混合子classes 一起工作
public class AllObjectContainer extends MyObjectContainer<MyObject<?>> {
public AllObjectContainer() {
super(MyObject.class); // compile error here
}
}
这不会编译,因为“构造函数 MyObjectContainer(Class) 未定义”。将“MyObject.class”转换为“Class>”是不可能的。
为了解决这个问题,我可以使用原始类型:
- 将
public class AllObjectContainer extends MyObjectContainer<MyObject<?>>
更改为public class AllObjectContainer extends MyObjectContainer<MyObject>
由于类型擦除,这会产生后果,所以我不喜欢这个解决方案。
或者我可以通过
启用投射
- 将
protected MyObjectContainer(Class<T> valueType) {
更改为 protected MyObjectContainer(Class<? extends T> valueType) {
(添加 ? extends
)
- 将
super(MyObject.class)
更改为super((Class<? extends MyObject<?>>) MyObject.class)
此方法有效,但转换被标记为未检查并且更改 MyMiddleContainer
-构造函数对扩展它的其他 class 有潜在的副作用。
有没有更好的解决方案?
所以,MyClass.class
是 Class<MyClass>
类型而不是 Class<MyClass<?>>
。
这真是一道关于反射的题
通常解决反射问题的好办法就是不使用反射。
我建议删除 Class
的使用并替换为您想要的操作界面。然后,如果您愿意,您可以在该接口的特定实现中放置反射污秽。
关于反射的评论和这段代码不是最佳实现的标志是真实有效的,每个偶然发现这个答案的人应该阅读并考虑它们。
然而,在我的例子中,完全摆脱反射是不可能的,因为 Class
值被传递给另一个不受我控制的 class - 无论是好不好是另外一题(我猜,答案是'no'),但不在本题范围内
我通过以下方式解决了我的问题:
- 从构造函数中删除了
valueType
参数
- 将
protected abstract Class<T> getValueType();
添加到 MyParentContainer
然后我通过以下方式实现了该方法:
public class IntContainer extends MyObjectContainer<IntObject> {
protected Class<T> getValueType() {
return IntObject.class;
}
}
public class AllObjectContainer extends MyObjectContainer<MyObject<?>> {
protected Class<T> getValueType() {
return (Class<MyObject<?>>) (Class<?>) MyObject.class;
}
}
双重演员阵容不好看,我完全知道这一点。但是在一个密闭的地方,显然是可以施法的,修复了“不能施法”的错误。
我有以下 class 层次结构:
public abstract class MyParentObject {}
public abstract class MyObject<T> extends MyParentObject {}
public abstract class MyParentContainer<T extends MyParentObject> {
private Class<T> valueType;
protected MyParentContainer(Class<T> valueType) {
this.valueType = valueType;
}
}
public abstract class MyObjectContainer<T extends MyObject<?>> extends MyParentContainer<T> {
protected MyObjectContainer(Class<T> valueType) {
super(valueType);
}
}
目前为止一切正常。 MyObject
有几个子classes 和几个容器classes 有一些子classes 作为valueType
,例如
public class IntObject extends MyObject<Integer> {}
public class IntContainer extends MyObjectContainer<IntObject> {
public IntContainer() {
super(IntObject.class);
}
}
现在我需要实现一个容器,尽管它与 MyObject
.
public class AllObjectContainer extends MyObjectContainer<MyObject<?>> {
public AllObjectContainer() {
super(MyObject.class); // compile error here
}
}
这不会编译,因为“构造函数 MyObjectContainer
为了解决这个问题,我可以使用原始类型:
- 将
public class AllObjectContainer extends MyObjectContainer<MyObject<?>>
更改为public class AllObjectContainer extends MyObjectContainer<MyObject>
由于类型擦除,这会产生后果,所以我不喜欢这个解决方案。
或者我可以通过
启用投射- 将
protected MyObjectContainer(Class<T> valueType) {
更改为protected MyObjectContainer(Class<? extends T> valueType) {
(添加? extends
) - 将
super(MyObject.class)
更改为super((Class<? extends MyObject<?>>) MyObject.class)
此方法有效,但转换被标记为未检查并且更改 MyMiddleContainer
-构造函数对扩展它的其他 class 有潜在的副作用。
有没有更好的解决方案?
所以,MyClass.class
是 Class<MyClass>
类型而不是 Class<MyClass<?>>
。
这真是一道关于反射的题
通常解决反射问题的好办法就是不使用反射。
我建议删除 Class
的使用并替换为您想要的操作界面。然后,如果您愿意,您可以在该接口的特定实现中放置反射污秽。
关于反射的评论和这段代码不是最佳实现的标志是真实有效的,每个偶然发现这个答案的人应该阅读并考虑它们。
然而,在我的例子中,完全摆脱反射是不可能的,因为 Class
值被传递给另一个不受我控制的 class - 无论是好不好是另外一题(我猜,答案是'no'),但不在本题范围内
我通过以下方式解决了我的问题:
- 从构造函数中删除了
valueType
参数 - 将
protected abstract Class<T> getValueType();
添加到MyParentContainer
然后我通过以下方式实现了该方法:
public class IntContainer extends MyObjectContainer<IntObject> {
protected Class<T> getValueType() {
return IntObject.class;
}
}
public class AllObjectContainer extends MyObjectContainer<MyObject<?>> {
protected Class<T> getValueType() {
return (Class<MyObject<?>>) (Class<?>) MyObject.class;
}
}
双重演员阵容不好看,我完全知道这一点。但是在一个密闭的地方,显然是可以施法的,修复了“不能施法”的错误。