Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I extend an ArrayList (is-a) or should I include it as a member (has-a)?

I'm making a simple program that maintains a list of numbers, and I want this list to also have a name. Which is the best approach: have my list class extend ArrayList or have it include an ArrayList member? In both cases, there would of course be a "name" String member.

The first approach means I only have to implement a getter & setter for the name, but I think this would tie my class too closely to a particular implementation? For example, if I wanted to later use a Vector, than I would have to change code everywhere.

The second approach would make it easier to change the implementation, but of course becomes quite annoying for now, since I have to implement a bunch of wrappers.

I've read the SO posts regarding inheritance vs. composition, and since my list is a type of ArrayList, I am leaning towards the first approach. However, is there any differences to the discussion because I'm extending a Collection class vs extending a general class? Or am I over-thinking this?

like image 275
red.october Avatar asked Mar 15 '11 02:03

red.october


People also ask

Can an ArrayList be extended?

As many other have said, yes, you can extend class ArrayList , but it is not something that you should normally do; it is not considered good practice in Java.

Can you set the size of an ArrayList?

When you create an ArrayList you can specify the initial capacity. For example: ArrayList<Integer> arrayList = new ArrayList<>(100); In this case, the initial capacity of the ArrayList will be 100.

How do you add an ArrayList to an ArrayList?

Approach: ArrayLists can be joined in Java with the help of Collection. addAll() method. This method is called by the destination ArrayList and the other ArrayList is passed as the parameter to this method. This method appends the second ArrayList to the end of the first ArrayList.

What is the size of ArrayList in Java?

The size of an ArrayList can be obtained by using the java. util. ArrayList. size() method as it returns the number of elements in the ArrayList i.e. the size.


2 Answers

In the long run it's generally better to include as a member than extend. This way it's more explicit what you want to allow, making it easier to test and hold to the contact of the class. If you simply extend ArrayList then it might not always be used as you intended. The trade-off of course is that you'll have to explicitly create pass-through methods for everything you do want to allow. Alternatively (or additionally) you might want to provide a method to get the underlying List, which you could wrap with an immutable collection to safeguard it from changes happening outside of the control of your class.

like image 157
WhiteFang34 Avatar answered Sep 27 '22 19:09

WhiteFang34


For the best of both worlds, use a Guava ForwardingList. Here's a simple example:

public class NamedList<E> extends ForwardingList<E> implements RandomAccess {
  // could also let the user provide the delegate list
  private final List<E> delegate = Lists.newArrayList();
  private String name;

  @Override protected List<E> delegate() {
    return delegate;
  }

  // constructors, getter, setter
}

By the way, the pitfalls of extending a concrete collection implementation rather than using composition are discuseed in Effective Java item 16 (in 2nd Ed.) "Favor composition over inheritance." One of the several issues mentioned has to do with unexpected behavior related to the interaction between methods in the superclass (e.g. add and addAll).

Guava's Forwarding* classes are an implementation of the solution suggested there.

like image 45
ColinD Avatar answered Sep 27 '22 20:09

ColinD