【问题标题】:Create an immutable subclass of ArrayList创建 ArrayList 的不可变子类
【发布时间】:2018-05-05 13:05:21
【问题描述】:

我正在设计一个简单的子类ArrayList<Color>。在我的应用程序上下文中,此列表充当“参考列表”,按照循环和明确定义的顺序返回 Color 对象。

@SuppressWarnings("serial")
public final class ColorList extends ArrayList<Color> {

    private static int colorIndex = -1;

    public ColorList() {

        this.add(Color.CYAN);
        this.add(Color.DARK_GRAY);
        this.add(Color.GRAY);
        this.add(Color.GREEN);
        this.add(Color.BLUE);
        this.add(Color.LIGHT_GRAY);
        this.add(Color.MAGENTA);
        this.add(Color.ORANGE);
        this.add(Color.PINK);
        this.add(Color.RED);
        this.add(Color.YELLOW);
    }

    //if the color chosen is not the last one, increment index and get it.
    public Color getNextColor() {
        Color color = null;
        if(colorIndex != this.size() - 1) {
            color = this.get(++colorIndex);
        }
        else {
            colorIndex = -1;
            color = this.get(++colorIndex);
        }
        return color;
    }

出于这个原因,我想让这个类不可变,因为它旨在成为一个只读列表,其内容在对象第一次实例化时定义,并在其整个生命周期内保持不变。同时,我需要能够利用 getNextColor() 来保持“循环”方式。

采取的方法

  1. 返回一个不可修改的引用。

    public static List<Color> getInstance(){
        return Collections.unmodifiableList(new ColorList());
    }
    

    这种方法的问题在于,通过返回一个 List 引用它 阻止我调用getNextColor() 方法,使我的课程毫无用处。 强制转换并不能解决问题,因为底层对象是 UnmodifiableRandomAccessList 的实例,不能转换为 ColorList

  2. 覆盖引用可选操作的方法

    @Override
    public boolean add(Color c) {
        throw new UnsupportedOperationException("color list is read-only");
    }
    <overridding other methods such as addAll, remove...>
    

    documentation 中所述,某些标记为“可选”的操作可能会或可能不会实现,具体取决于集合的目的。但这会阻止我首先添加颜色,就像我在实例化对象时在构造函数中所做的那样。

    我想我可能误解了一些关键的设计方面。有没有办法让我的类不可变,而不限制它的(已经是基本的)功能?
    编辑:为了向后兼容,这个类需要显式扩展 ArrayList。因此我不能使用包装类,尽管我也认为这将是最正确的方法。

【问题讨论】:

  • 是否需要实现List?您希望如何使用ColorList?如果不需要列表功能,也许可以避免复杂性......
  • 为什么不直接使用Collections.unmodifiableList(Arrays.asList(Color.CYAN, Color.DARK_GRAY, ...))
  • @ErnestKiwele 需要扩展 ArrayList
  • 如果你必须扩展ArrayList,它是可变的,那么你唯一的选择是覆盖改变状态的方法(你的帖子中的选项2)。 附带说明:您的 colorIndex 字段可能是您的“不变性”实现中的一个弱点。
  • 我能想到另一种选择:覆盖iterator() 方法并提供您自己的Iterator&lt;Color&gt; 实现,它总是为hasNext 返回true 并具有index 字段。这样,您将从 ColorList 中删除可变状态并将其放入您的 Iterable 类中,您将在每次调用 colorIterator.iterator() 时创建一个实例。

标签: java arraylist collections immutability


【解决方案1】:

如果您希望 List 的内容是不可变的,那么您的构造函数可以工作,只有您应该调用 super.add(...) 而不是 this.add(...);这样做意味着您对add(...) 的覆盖将是明智的,可以保护列表免受外部干扰,同时允许构造函数为您初始化对象。

您的问题不清楚,但如果您还想阻止直接访问 List 中的对象,您显然也可以根据需要覆盖 get(...) 和其他方法 - 尽管如果您这样做,那么您的 getNextColor(...) 方法应该调用super.get(...) 而不是 this.get(...)

最后,您可能不需要 colors 成员变量,因为您正在扩展一个 List - 没有必要在其中嵌套另一个 List。

【讨论】:

  • 为不明确表示歉意,如果您介意指出应该更好地解释的内容,我将相应地进行编辑
  • 没问题,我的意思只是不清楚您给出的要求 - 您是否需要防止直接访问数组元素。此外,作为事后的想法,如果这是学校/大学的工作,你可能会因为重新发明轮子而被打分(ArrayList 扩展了 AbstractList,它实现了 Iterable,并提供了一个“next(...)”方法)。
【解决方案2】:

认为在您的情况下,最好使用组合而不是继承。在这种情况下,您只是不公开可以修改颜色列表的方法。

这是一个示例代码

public final class ColorList {
    private final Color[] values;
    private int colorIndex;

    public ColorList(Color... colors) {
        this.values = colors;
    }

    public Color getNextColor() {
        if (colorIndex == values.length) colorIndex = 0;

        return values[colorIndex++];
    }

    public static void main(String[] args) {
        ColorList cl = new ColorList(Color.CYAN, Color.YELLOW, Color.WHITE);

        System.out.println(cl.getNextColor());
        System.out.println(cl.getNextColor());
        System.out.println(cl.getNextColor());
        System.out.println(cl.getNextColor());
    }
}

在您提供的源代码中,有几点值得一提:

  • colorIndex 变量是静态的,因此它在 ColorList 类的所有实例之间共享。如果多个实例调用 getNextColor() 结果将不一致。也许您有创建 Singleton 类的想法,因此只有一个实例是可能的?
  • 代码中的颜色列表在编译时始终相同且已知,因此不可能创建具有不同颜色集的 ColorList 实例。应该是这样吗?

【讨论】:

  • 我的错,之前我实现了单例这样的类,但由于设计限制被告知我不能,并且忘记在发布代码之前删除“静态”。组合是我首先想到的解决方案,遗憾的是为了与外部代码兼容,我被告知要设计一个专门扩展 ArrayList 的类,但它是不可变的。是的,颜色应该总是相同的(至少现在是这样),所以我只是对它们进行了硬编码。不错的解决方案,有趣的是选择使用带有可变长度参数的构造函数
猜你喜欢
  • 1970-01-01
  • 2014-12-29
  • 2010-09-26
  • 1970-01-01
  • 1970-01-01
  • 2018-11-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-15
相关资源
最近更新 更多