java - 扩展 java ArrayList

标签 java arraylist extend

我想扩展 ArrayList 以便为特定类添加一些方法,这些类的实例将由扩展的 ArrayList 持有。下面是一个简化的说明性代码示例。

这对我来说似乎很明智,但我是 Java 的新手,我看到其他问题不鼓励扩展 ArrayList,例如 Extending ArrayList and Creating new methods .我对 Java 的了解不够,无法理解这些反对意见。

在我之前的尝试中,我最终在 ThingContainer 中创建了一些方法,这些方法本质上是对 ArrayList 的传递,因此扩展似乎更容易。

是否有更好的方法来完成我想做的事情?如果可以,应该如何实现?

import java.util.*;

class Thing {
    public String name;
    public int amt;

    public Thing(String name, int amt) {
        this.name = name;
        this.amt = amt;
    }

    public String toString() {
        return String.format("%s: %d", name, amt);
    }

    public int getAmt() {
        return amt;
    }
}

class ThingContainer extends ArrayList<Thing> {
    public void report() {
        for(int i=0; i < size(); i++) {
            System.out.println(get(i));
        }
    }

    public int total() {
        int tot = 0;
        for(int i=0; i < size(); i++) {
            tot += ((Thing)get(i)).getAmt();
        }
        return tot;
    }

}

public class Tester {
    public static void main(String[] args) {
        ThingContainer blue = new ThingContainer();

        Thing a = new Thing("A", 2);
        Thing b = new Thing("B", 4);

        blue.add(a);
        blue.add(b);

        blue.report();
        System.out.println(blue.total());

        for (Thing tc: blue) {
            System.out.println(tc);
        }
    }
}

最佳答案

该答案中没有任何内容阻止扩展 ArrayList;存在语法问题。存在类扩展,因此我们可以重用代码。

扩展类的一般反对意见是 "favor composition over inheritance"讨论。扩展并不总是首选机制,但这取决于您实际在做什么。

根据要求编辑组合示例。

public class ThingContainer implements List<Thing> { // Or Collection based on your needs.
    List<Thing> things;
    public boolean add(Thing thing) { things.add(thing); }
    public void clear() { things.clear(); }
    public Iterator<Thing> iterator() { things.iterator(); }
    // Etc., and create the list in the constructor
}

您不一定需要公开一个完整的列表接口(interface),只是集合,或者根本没有。但是,不公开任何功能会大大降低通用性。

在 Groovy 中,您只需使用 @Delegate 注释即可自动构建方法。 Java可以使用Project Lombok@Delegate 注释来做同样的事情。我不确定 Lombok 将如何公开接口(interface),或者是否公开。

我在使用 glowcoder,在这种情况下,我没有发现扩展有任何根本性的错误——这实际上是哪种解决方案更适合问题的问题。

编辑有关继承如何违反封装的详细信息

有关详细信息,请参阅 Bloch 的 Effective Java,第 16 项。

如果子类依赖父类(super class)的行为,而父类(super class)的行为发生变化,则子类可能会崩溃。如果我们不控制父类(super class),这可能会很糟糕。

这是一个具体的例子,从书中摘录(抱歉,Josh!),采用伪代码,并进行了大量解释(所有错误都是我的)。

class CountingHashSet extends HashSet {
    private int count = 0;
    boolean add(Object o) {
        count++;
        return super.add(o);
    }
    boolean addAll(Collection c) {
        count += c.size();
        return super.addAll(c);
    }
    int getCount() { return count; }
}

然后我们使用它:

s = new CountingHashSet();
s.addAll(Arrays.asList("bar", "baz", "plugh");

它返回……三个?没有。六。为什么?

HashSet.addAll() 是在 HashSet.add() 上实现的,但这是一个内部实现细节。我们的子类 addAll() 添加三个,调用 super.addAll(),这会调用 add(),这也会增加计数。

我们可以删除子类的 addAll(),但现在我们依赖于父类(super class)的实现细节,这可能会改变。我们可以修改我们的 addAll() 以在每个元素上迭代和调用 add(),但现在我们正在重新实现父类(super class)行为,这违背了目的,并且可能并不总是如果父类(super class)行为依赖于对私有(private)成员的访问,则有可能。

或者父类(super class)可能会实现我们的子类没有的新方法,这意味着我们类的用户可能会通过直接调用父类(super class)方法无意中绕过预期行为,因此我们必须跟踪父类(super class) API 以确定何时以及是否,子类应该改变。

关于java - 扩展 java ArrayList,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8098615/

相关文章:

python - 如何从这两个列表列表中删除出现在两个列表列表中的可能列表?

java - 如何将一个类中的对象分配给另一个类以及如何计算 ArrayList 中的 double 和 int?

java - 如何提高Java多线程性能?从 NoSQL 数据库(如 Redis)与 ArrayList 保存/加载数据的时间效率?

css - SCSS @extend inside media query alternatives to avoid duplicate properties

java - 更好地扩展一个类或直接修改它?

java - IllegalStateException 与 UnsupportedOperationException

java - 仅获取路径目录并丢弃Java中的文件

java - 实际参数列表和正式参数列表的长度不同?

javascript - 我可以使用原型(prototype) 'extend' jQuery 对象吗?

Java生成不重复随机数