java中的不可变类型(尤其是集合)和协方差

java中的不可变类型(尤其是集合)和协方差,java,collections,immutability,Java,Collections,Immutability,假设我有一个类WidgetHolder,它保存Widget实例。在内部,我使用列表对其进行备份。我保证它是不可变的,因此在构建之后,不会向持有者添加任何小部件 WidgetHolder还公开了一个getWidgets()操作,该操作返回小部件列表的不可变视图 我希望有一个派生的SpecificWidgetHolder类,该类包含SpecificWidget实例,其getWidgets()的返回类型为Collection 我有同样的保证,即SpecificWidgetHolder构造函数接受Spe

假设我有一个类
WidgetHolder
,它保存
Widget
实例。在内部,我使用
列表对其进行备份。我保证它是不可变的,因此在构建之后,不会向持有者添加任何小部件

WidgetHolder
还公开了一个
getWidgets()
操作,该操作返回小部件列表的不可变视图

我希望有一个派生的
SpecificWidgetHolder
类,该类包含
SpecificWidget
实例,其
getWidgets()
的返回类型为
Collection

我有同样的保证,即
SpecificWidgetHolder
构造函数接受
SpecificWidget
实例的集合,并且不会以任何方式修改它

鉴于
WidgetHolder
SpecificWidgetHolder
都是不可变的,证明通用不变性的常见反对意见似乎并不适用(?)

有没有一种干净的方式用Java来表达这一点

谢谢

试试这个:

public class WidgetHolder<T extends Widget>
{
  public List<T> getWidgets()
  {
    return (widgets);
  }

  private List<T> widgets;

} // class WidgetHolder

public class SpecificWidgetHolder extends WidgetHolder<SpecificWidget>
{
}
公共类WidgetHolder
{
公共列表getWidgets()
{
返回(小部件);
}
私有列表小部件;
}//类WidgetHolder
公共类SpecificWidgetHolder扩展了WidgetHolder
{
}
试试这个:

public class WidgetHolder<T extends Widget>
{
  public List<T> getWidgets()
  {
    return (widgets);
  }

  private List<T> widgets;

} // class WidgetHolder

public class SpecificWidgetHolder extends WidgetHolder<SpecificWidget>
{
}
公共类WidgetHolder
{
公共列表getWidgets()
{
返回(小部件);
}
私有列表小部件;
}//类WidgetHolder
公共类SpecificWidgetHolder扩展了WidgetHolder
{
}

您描述的场景非常常见:您在内部存储对象集合,并希望公开此集合的只读版本。这通常使用以下方法(以及其他集合类型的特定方法)完成:

  • 使用特定类型,您知道该类型可分配给超类的类型:

    public List<SpecificWidget> getWidgets()
    
  • 在如何使用该类方面存在细微的差异。特别是,关于“特定性”的信息是否可供调用者使用。我试图在这个例子中指出这一点:

    // With option 1, you only receive Widgets - even
    // from a SpecificWidgetHolder
    List<? extends Widget> widgets = specificWidgetHolder.getWidgets();
    Widget widget = widgets.get(0);
    
    // With option 3., you still know that a SpecificWidgetHolder
    // provides a list of SpecificWidgets
    List<? extends SpecificWidget> specificWidgets = specificWidgetHolder.getWidgets();
    SpecificWidget specificWidget = specificWidgets.get(0);
    
    //使用选项1,您只接收小部件-甚至
    //从一个特定的WidgetHolder
    
    List您描述的场景非常常见:您在内部存储对象集合,并希望公开该集合的只读版本。这通常使用以下方法(以及其他集合类型的特定方法)完成:

  • 使用特定类型,您知道该类型可分配给超类的类型:

    public List<SpecificWidget> getWidgets()
    
  • 在如何使用该类方面存在细微的差异。特别是,关于“特定性”的信息是否可供调用者使用。我试图在这个例子中指出这一点:

    // With option 1, you only receive Widgets - even
    // from a SpecificWidgetHolder
    List<? extends Widget> widgets = specificWidgetHolder.getWidgets();
    Widget widget = widgets.get(0);
    
    // With option 3., you still know that a SpecificWidgetHolder
    // provides a list of SpecificWidgets
    List<? extends SpecificWidget> specificWidgets = specificWidgetHolder.getWidgets();
    SpecificWidget specificWidget = specificWidgets.get(0);
    
    //使用选项1,您只接收小部件-甚至
    //从一个特定的WidgetHolder
    
    列表为什么不能应用通用逻辑?类似这样的
    WidgetHolder
    T getWidget()
    方法。为什么不能应用通用逻辑?类似这样的
    WidgetHolder
    T getWidget()
    方法。很快:)很快:)谢谢你的回答!但如果您能解释一下不可修改列表示例是如何编译的,那将是一件有趣的事情。AFAICT
    Collections.unmodifiableList
    返回实现
    List
    接口的类的实例,包括
    add
    等?仅供我个人参考,这里有详细说明:谢谢你的回答!但如果您能解释一下不可修改列表示例是如何编译的,那将是一件有趣的事情。AFAICT
    Collections.unmodifiableList
    返回实现
    List
    接口的类的实例,包括
    add
    等?仅供我参考,这里有详细说明:
    public List<SpecificWidget> getWidgets()
    
    public List<? extends SpecificWidget> getWidgets()
    
    // With option 1, you only receive Widgets - even
    // from a SpecificWidgetHolder
    List<? extends Widget> widgets = specificWidgetHolder.getWidgets();
    Widget widget = widgets.get(0);
    
    // With option 3., you still know that a SpecificWidgetHolder
    // provides a list of SpecificWidgets
    List<? extends SpecificWidget> specificWidgets = specificWidgetHolder.getWidgets();
    SpecificWidget specificWidget = specificWidgets.get(0);