扩展java ArrayList

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

这对我来说似乎很明智,但我对Java很新,我看到其他一些不鼓励扩展ArrayList的问题,例如Extending ArrayList和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 { 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; 有一个语法问题。 存在类扩展,因此我们可以重用代码。

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

根据要求编辑组合示例。

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

您不一定需要公开完整列表界面,只需要集合,或者根本不需要 。 但是,没有公开任何function会大大降低一般的实用性。

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

我使用的是glowcoder,在这种情况下我没有看到任何根本性的扩展错误 – 这真的是一个解决方案更适合问题的问题。

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

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

如果子类依赖于超类行为,并且超类的行为发生更改,则子类可能会中断。 如果我们不控制超类,那可能是坏事。

这是一个具体的例子,从书中解脱(对不起乔希!),用伪代码,并大量释义(所有错误都是我的)。

 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() ,它也会增加count。

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

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

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

 public class ThingContainer { private ArrayList myThings; public ThingContainer(){ myThings = new ArrayList(); } public void doSomething(){ //code } public Iterator getIter(){ return myThings.iterator(); } } 

您应该只在您的ThingContainer类中包装ArrayList。 然后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 } } 

这是我的建议:

 interface ThingStorage extends List { public int total(); } class ThingContainer implements ThingStorage { private List things = new ArrayList(); public boolean add(Thing e) { return things.add(e); } ... remove/size/... etc public int total() { int tot = 0; for(int i=0; i < size(); i++) { tot += ((Thing)get(i)).getAmt(); } return tot; } } 

实际上并不需要report() 。 toString()可以完成剩下的工作。