扩展 java ArrayList [英] Extending a java ArrayList

查看:22
本文介绍了扩展 java ArrayList的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'd like to extend ArrayList to add a few methods for a specific class whose instances would be held by the extended ArrayList. A simplified illustrative code sample is below.

这对我来说似乎很明智,但我对 Java 很陌生,我看到其他不鼓励扩展 ArrayList 的问题,例如 扩展 ArrayList 并创建新方法.我对 Java 的了解不够了解这些反对意见.

This seems sensible to me, but I'm very new to Java and I see other questions which discourage extending ArrayList, for example Extending ArrayList and Creating new methods. I don't know enough Java to understand the objections.

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

In my prior attempt, I ending up creating a number of methods in ThingContainer that were essentially pass-throughs to ArrayList, so extending seemed easier.

有没有更好的方法来做我想做的事?如果是,应该如何实施?

Is there a better way to do what I'm trying to do? If so, how should it be implemented?

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;存在语法问题.存在类扩展,因此我们可以重用代码.

Nothing in that answer discourages extending ArrayList; there was a syntax issue. Class extension exists so we may re-use code.

对扩展类的一般反对意见是赞成组合而不是继承" 的讨论.扩展并不总是首选机制,但这取决于您实际在做什么.

The normal objections to extending a class is the "favor composition over inheritance" discussion. Extension isn't always the preferred mechanism, but it depends on what you're actually doing.

根据要求编辑合成示例.

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
}

您不一定需要公开一个完整的列表界面,只是集合,或者根本不需要.但是,不公开任何功能会大大降低一般用途.

You wouldn't necessarily need to expose a full list interface, just collection, or none at all. Exposing none of the functionality greatly reduces the general usefulness, though.

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

In Groovy you can just use the @Delegate annotation to build the methods automagically. Java can use Project Lombok's @Delegate annotation to do the same thing. I'm not sure how Lombok would expose the interface, or if it does.

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

I'm with glowcoder, I don't see anything fundamentally wrong with extension in this case--it's really a matter of which solution fits the problem better.

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

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

See Bloch's Effective Java, Item 16 for more details.

如果子类依赖于超类的行为,并且超类的行为发生变化,则子类可能会崩溃.如果我们不控制超类,这可能很糟糕.

If a subclass relies on superclass behavior, and the superclass's behavior changes, the subclass may break. If we don't control the superclass, this can be bad.

这是一个具体的例子,摘自书中(抱歉 Josh!),用伪代码编写,并经过大量释义(所有错误都是我的错误).

Here's a concrete example, lifted from the book (sorry Josh!), in pseudo-code, and heavily paraphrased (all errors are mine).

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");

它返回...三个?不.六.为什么?

And it returns... three? Nope. Six. Why?

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

HashSet.addAll() is implemented on HashSet.add(), but that's an internal implementation detail. Our subclass addAll() adds three, calls super.addAll(), which invokes add(), which also increments count.

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

We could remove the subclass's addAll(), but now we're relying on superclass implementation details, which could change. We could modify our addAll() to iterate and call add() on each element, but now we're reimplementing superclass behavior, which defeats the purpose, and might not always be possible, if superclass behavior depends on access to private members.

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

Or a superclass might implement a new method that our subclass doesn't, meaning a user of our class could unintentionally bypass intended behavior by directly calling the superclass method, so we have to track the superclass API to determine when, and if, the subclass should change.

这篇关于扩展 java ArrayList的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆