Java在佩奇构造中可能需要不必要的extends关键字

umuewwlo  于 2023-01-24  发布在  Java
关注(0)|答案(1)|浏览(107)

我有一个代码示例,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())));
  }
}
gstyhher

gstyhher1#

DataContainer<ExtendedData>不能赋值给DataContainer<Data>,但是由于DataContainer是一个生成器,所以在这里使用? extends Data(佩奇中的PE)是有意义的,因为两种类型都可以生成Data类型的值:

DataContainer<ExtendedData> a = new DataContainer<>(new ExtendedData());
DataContainer<Data> b = new DataContainer<>(new Data());

DataContainer<? extends Data> a2 = a, b2 = b;

Data d1 = a2.getData(), d2 = b2.getData();

换句话说,DataContainer<ExtendedData>DataContainer<Data>都是DataContainer<? extends Data>的 * 子类型 *,类DataContainerfinal的事实是无关紧要的。
所以,声纳警告在这里是错误的。建议避免final类作为上限只有在final类不是泛型的情况下才有意义。
尽管ExtendedDataData的子类,但DataContainer<ExtendedData>不能赋值给DataContainer<Data>的相同推理也适用于泛型类型的List
DataContainer<ExtendedData>DataContainer<? extends Data>的子类型,但是List<DataContainer<ExtendedData>不能分配给List<DataContainer<? extends Data>>
当列表充当生产者时,您必须求助于? extends,即允许您从中获取DataContainer<? extends Data>元素。

List<DataContainer<ExtendedData>> list1
    = Collections.singletonList(new DataContainer<>(new ExtendedData()));
List<DataContainer<Data>> list2
    = Collections.singletonList(new DataContainer<>(new Data()));

// List<DataContainer<? extends Data>> list3 = list1; // does not compile
// List<DataContainer<? extends Data>> list4 = list2; // neither does this

// both lists can act as producer of DataContainer<? extends Data>
List<? extends DataContainer<? extends Data>> list3 = list1; 
Data d3 = list3.get(0).getData();
List<? extends DataContainer<? extends Data>> list4 = list2;
Data d4 = list4.get(0).getData();

注意,由于DataContainer<Data>DataContainer<ExtendedData>是不同的类型,都不是另一个的子类型,因此无法为List<DataContainer<Data>>List<DataContainer<ExtendedData>>定义允许添加两种类型的元素的公共消费者类型。
请记住,使用调用类型推断,结果乍看起来似乎与这些规则相矛盾。

List<DataContainer<Data>> list
    = Collections.singletonList(new DataContainer<>(new ExtendedData()));

你不会得到错误。不是因为你可以把DataContainer<ExtendedData>加到List<DataContainer<Data>上,而是因为在这种情况下,编译器推断DataContainer<Data>是要构造的类型。并且把ExtendedData的示例传递给DataContainer<Data>的构造函数是有效的。

相关问题