扩展 java ArrayList

2022-09-02 22:24:50

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

这对我来说似乎很合理,但我对Java很陌生,我看到其他问题阻碍了RayList的扩展,例如扩展ArrayList和创建新方法。我对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);
        }
    }
}

答案 1

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

对扩展类的正常反对意见是“赞成组合而不是继承”的讨论。扩展并不总是首选机制,但它取决于您实际在做什么。

根据要求编辑作文示例。

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
}

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

在Groovy中,你可以使用注释来自动构建方法。Java可以使用Project Lombok的注释来做同样的事情。我不确定龙目岛将如何公开界面,或者它是否公开。@Delegate@Delegate

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

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

有关详细信息,请参阅布洛赫的《有效 Java》第 16 项。

如果子类依赖于超类行为,并且超类的行为发生了变化,则该子类可能会中断。如果我们不控制超类,这可能很糟糕。

这是一个具体的例子,从书中摘录(对不起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()addAll()add()

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


答案 2

我不认为扩展arrayList是必要的。

public class ThingContainer {

    private ArrayList<Thing> myThings;

    public ThingContainer(){
        myThings = new ArrayList<Thing>();
    }

    public void doSomething(){
         //code
    }

    public Iterator<Thing> getIter(){
        return myThings.iterator();
    }
}

你应该把 ArrayList 包装在你的 ThingContainer 类中。然后,ThingContainer可以拥有您需要的任何处理方法。无需扩展 ArrayList;只要保留一个私人成员。希望这有帮助。

您可能还需要考虑创建一个表示 Thing 类的接口。这为您提供了更大的可扩展性灵活性。

public Interface ThingInterface {
   public void doThing();
}

...

public OneThing implements ThingInterface {
   public void doThing(){
        //code
   }
}

public TwoThing implements ThingInterface {
   private String name;
   public void doThing(){
        //code
   }
}

推荐