我有自己的通用,如:
public interface SelfConfigurable<E extends SelfConfigurable<E>> {
E configure(JsonObject settings);
}
另一个界面,也是泛型类型,扩展了我之前的界面:
public interface ConfigurableSegmentFilter<T> extends SegmentFilter<T>, SelfConfigurable<ConfigurableSegmentFilter<T>> {
}
我也有像这样的实现
public abstract class ConfigurableSegmentFilterSkeleton<T> implements ConfigurableSegmentFilter<T> {
@Override
public ConfigurableSegmentFilter<T> configure(JsonObject settings) {
... }
}
我通过反射实例化对象,并希望在添加到List之前配置它:
List<ConfigurableSegmentFilter<?>> result = ...
ConfigurableSegmentFilter newFilter = Reflection.newInstance() + casting
result.add(newFilter.configure(...)); <-- compile error 'cannot be applien to SelfConfigurable' but why?
//when i call to configure directly i am getting:
SelfConfigurable configure = newFilter.configure(...) <-- why SelfConfigurable??
我收到编译错误!它告诉我xxx.configure()返回SelfConfigurable接口而不是ConfigurableSegmentFilter,我无法理解它为什么会发生。
还有一件事,当我将newFilter与开始按预期工作的通配符绑定时
List<ConfigurableSegmentFilter<?>> result = ...
ConfigurableSegmentFilter<?> newFilter = ... //<-- bound with <?>
result.add(newFilter.configure(...)); <-- No error! But why?
ConfigurableSegmentFilter vs ConfigurableSegmentFilter<?>
答案 0 :(得分:0)
'raw'类型与通用类型参数设置为'Object'的通用类型不同。
这样做的原因是为了避免运行时强制转换异常。
例如,让我们考虑一个涉及'java.util.List'类的简单场景:
List a = ... # a elements could be a mix of any type.
List<?> b = ... # b elements are all instance of a known class '?'.
List<Object> c = ... # c elements are all instances of Object.
List<String> d = ... # d elements are all instances of String.
应该清楚为什么将任何其他列表中的元素移动到'd'必须有问题,因为不能保证这些元素是'String's
然而,其他任何组合呢?
a,c或d - &gt;湾
b.addAll(c); // error!!!
'?'这里代表一个未知类型...例如它可能是String,在这种情况下我们回到明确的情况c - &gt; d。这个限制到位的原因是,当实际知道集合的类型参数的一些其他代码(比如String)并且正在消耗它时,防止运行时异常会拉动非字符串实例导致运行时强制转换异常
b,a,d - &gt; c或b,c,d - &gt;一个。
允许,毕竟什么'?'所有实例都是'对象',所以没问题。一个
还要注意一些参考指定我的问题(至少是一个警告):
c = a; // unchecked warning;
c = d; // error as now you would be able to add non-strings to 'd' thru 'c'.
c = b; // error, same as above where the the element type is unknown.
a = d; a = b; // same as with 'c'.
d = c; d = a; // error for obvious reason.
答案 1 :(得分:0)
当您使用原始类型的表达式时,您&#34;关闭&#34;使用该表达式执行的所有泛型,包括方法签名和超类型签名。这意味着,原始类型ConfigurableSegmentFilter
仅扩展原始类型SelfConfigurable
,因此其实例方法.configure()
将返回E
的删除,即SelfConfigurable
。
这就是为什么你应该避免使用原始类型,因为它们只是为了向后兼容。当type参数未知时,您可以使用通配符参数化类型。