我有一个代码示例,Java强迫我在佩奇构造中的final类上使用extends
关键字。我不明白确切的原因。代码可以在下面或https://onecompiler.com/java/3yvf4g97f中找到。编译器无法编译名为process
的方法。如果我删除方法process
,那么SonarLint将触发名为processPecs
的方法违反规则https://rules.sonarsource.com/java/RSPEC-4968。或者这是一个误报?有没有更好的方法来“处理任意数据”?我需要在这里抑制SonarLint的警告并提交一个SonarLint的bug报告吗?
import java.util.List;
class PecsTest {
static final class DataContainer<D> {
final D data;
public DataContainer(D data) {
this.data = data;
}
D getData() {
return data;
}
}
static class Processor<D> {
@SuppressWarnings("unchecked")
List<DataContainer<D>> processPecs(List<? extends DataContainer<? super D>> list) {
return (List<DataContainer<D>>) list;
}
@SuppressWarnings("unchecked")
List<DataContainer<D>> process(List<DataContainer<? super D>> list) {
return (List<DataContainer<D>>) list;
}
}
static class Data {
}
static class ExtendedData extends Data {
}
public static void main(String[] args) {
new Processor<Data>().processPecs(List.of(new DataContainer<>(new ExtendedData())));
new Processor<ExtendedData>().processPecs(List.of(new DataContainer<>(new Data())));
}
}
1条答案
按热度按时间gstyhher1#
DataContainer<ExtendedData>
不能赋值给DataContainer<Data>
,但是由于DataContainer
是一个生成器,所以在这里使用? extends Data
(佩奇中的PE)是有意义的,因为两种类型都可以生成Data
类型的值:换句话说,
DataContainer<ExtendedData>
和DataContainer<Data>
都是DataContainer<? extends Data>
的 * 子类型 *,类DataContainer
是final
的事实是无关紧要的。所以,声纳警告在这里是错误的。建议避免final类作为上限只有在final类不是泛型的情况下才有意义。
尽管
ExtendedData
是Data
的子类,但DataContainer<ExtendedData>
不能赋值给DataContainer<Data>
的相同推理也适用于泛型类型的List
。DataContainer<ExtendedData>
是DataContainer<? extends Data>
的子类型,但是List<DataContainer<ExtendedData>
不能分配给List<DataContainer<? extends Data>>
。当列表充当生产者时,您必须求助于
? extends
,即允许您从中获取DataContainer<? extends Data>
元素。注意,由于
DataContainer<Data>
和DataContainer<ExtendedData>
是不同的类型,都不是另一个的子类型,因此无法为List<DataContainer<Data>>
和List<DataContainer<ExtendedData>>
定义允许添加两种类型的元素的公共消费者类型。请记住,使用调用类型推断,结果乍看起来似乎与这些规则相矛盾。
你不会得到错误。不是因为你可以把
DataContainer<ExtendedData>
加到List<DataContainer<Data>
上,而是因为在这种情况下,编译器推断DataContainer<Data>
是要构造的类型。并且把ExtendedData
的示例传递给DataContainer<Data>
的构造函数是有效的。