扩展一个Java的ArrayList [英] Extending a java ArrayList

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

问题描述

我想延长的ArrayList添加一些方法为特定的类,其实例将被扩展的ArrayList举行。简化说明code样品如下。

这似乎是明智的给我,但我很新的Java和我看到的劝阻延长ArrayList的其他问题,例如<一个href=\"http://stackoverflow.com/questions/6524711/extending-arraylist-and-creating-new-methods\">Extending ArrayList和创建新的方法的。我不知道足够的Java了解反对意见。

在我以前的尝试,我结束了造就了一批在ThingContainer的方法基本上是道直通到ArrayList中,所以似乎延伸更容易。

有没有更好的办法做我想要做什么?如果是这样,应该怎样执行?

 进口的java.util。*;类事情{
    公共字符串名称;
    公众诠释AMT;    公共物(字符串名称,诠释AMT){
        this.name =名称;
        this.amt = AMT;
    }    公共字符串的toString(){
        返回的String.format(%S:%D,名称,AMT);
    }    公众诠释getAmt(){
        返回AMT;
    }
}类ThingContainer扩展的ArrayList&LT;&东西GT; {
    公共无效报告(){
        的for(int i = 0; I&LT;尺寸();我++){
            的System.out.println(获得(一));
        }
    }    公众诠释共有(){
        INT TOT = 0;
        的for(int i = 0; I&LT;尺寸();我++){
            TOT + =((事)获得(I))getAmt()。
        }
        返回TOT;
    }}公共类测试仪{
    公共静态无效的主要(字串[] args){
        ThingContainer蓝色=新ThingContainer();        事情=新的东西(A,2);
        事B =新的东西(B,4);        blue.add(一);
        blue.add(二);        blue.report();
        的System.out.println(blue.total());        对于(事TC:蓝色){
            的System.out.println(TC);
        }
    }
}


解决方案

在这个问题的答案没有什么不鼓励扩大ArrayList的;有语法问题。类扩展的存在,所以我们可以重复使用code。

正常反对延长一类是讨论在继承青睐组成。扩展并不总是preferred机制,但它取决于你实际上在做什么。

Edit(编辑)的要求,组成例子。

 公共类ThingContainer实现列表与LT;东西&GT; {//或集合根据您的需求。
    清单&LT;&东西GT;事情;
    公共布尔附加(物物){things.add(事); }
    公共无效清除(){things.clear(); }
    公共迭代器&LT;&东西GT;迭代(){things.iterator(); }
    //等等,并在构造创建列表
}

您不一定会的需求的公开的完整列表界面,只需采集,或根本没有。的功能没有露出大大降低了一般用途,但。

在Groovy中你可以使用 @Delegate 标注,自动将建立的方法。 Java可以使用的项目龙目岛 @Delegate 注释做一样。我不知道龙目岛将如何暴露的接口,或者如果它。

我和辉光codeR,我看不出有什么根本性的错误延伸在这种情况下 - 这是真的,其中适合解决问题的更好的事情

编辑了解有关继承如何破坏封装细节

请参阅Bloch的Effective Java的第16项的更多细节。

如果一个子类依赖于超类的行为,以及超类的行为变化,子类可能会断裂。如果我们不控制的超类,这可不好。

下面是一个具体的例子,从书(对不起乔希!),在假code和大量转述解除(所有的错误都是我的)。

 类CountingHashSet扩展HashSet的{
    私人诠释计数= 0;
    布尔加(对象o){
        算上++;
        返回super.add(O);
    }
    布尔的addAll(集三){
        数+ = c.size();
        返回super.addAll(C);
    }
    INT getCount将(){返​​回计数; }
}

然后,我们使用它:

  S =新CountingHashSet();
s.addAll(Arrays.asList(酒吧,巴兹,plugh);

和返回...三?不。六。为什么呢?

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

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

或超有可能实现的,我们的子类不,这意味着我们班的用户可能会无意中绕过直接调用父类方法预期行为的新方法,所以我们要跟踪超API来确定何时,如果,子类应该改变。

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.

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.

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

解决方案

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.

Edit for composition example as requested.

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.

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.

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.

Edit for details regarding how inheritance can violate encapsulation

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.

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; }
}

Then we use it:

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

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

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.

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.

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天全站免登陆