我想扩展 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/