Skip to content

Programming by Design

If you're not prepared to be wrong, you'll never come up with anything original. – Sir Ken Robinson

  • About
  • Java-PbD
  • C-PbD
  • ASM-PbD
  • Algorithms
  • Other

Chapter 10 – Vector, ArrayList and Enumerations

Posted on June 2, 2019January 30, 2025 By William Jojo
Java Book

(Updated January 12, 2025)

Table of contents

    Overview
    Autoboxing and Auto-Unboxing
    The Vector Class
    The ArrayList Class
    Enumerations
    Color Vector Part II
    The instanceof Operator
    Quiz
    Exercises

Overview

The use of arrays has opened up many possibilities for collecting related data together. This is just the beginning of collecting data of varying forms into containers of varying shapes and sizes. The array is a valuable and productive tool. Still, it is also limited because we cannot directly increase the length of an already instantiated array object. (Yes, we can create a longer array and then copy the contents to the new array as well pushing and pull the data within the array (see Chapter 9 – Managing Arrays.)

Enter the Vector. A Vector is essentially an array of objects with the same limitations as any other array form. The Vector, however, takes the array to the next level; that is, it provides an intrinsic mechanism to extend the array when there is no longer any space to hold additional data. There are also mechanisms to shrink the space and insert and remove objects from the middle of the array, closing the gap made by the removal. (Again, see Chapter 9 – Managing Arrays.)

However, before we begin working with vectors, we need to revisit the wrapper classes and discuss some details that have been tucked away for a while.


Autoboxing and Auto-Unboxing

The Java language changed the wrapper class handling, starting with JDK 5.0. (See Chapter 3 wrapper classes.)

Autoboxing is the act of Java automatically calling on the appropriate constructor and methods when a primitive type is used where an object is expected. The compiler and runtime automatically compensate when there is a compatible wrapper class.

Auto-unboxing is the extraction of the primitive data from the object (i.e., intValue()) so that it can be used in simple expressions where primitive data is expected.

This is demonstrated in Example 1.

Boxing.java
public class Boxing {

    public static void main(String[] args) {

        int x, y;
        Integer xobj, yobj;

        // Simple primitive types
        x = 10;
        y = 15;
        // int vars boxed to Integer and toString() invoked.
        System.out.println("x is " + x);
        System.out.println("y is " + y);
        System.out.println("x * y = " + x * y + "\n");

        // int vars are boxed to Integer
        xobj = x;
        yobj = y;
        // toString() invoked
        System.out.println("xobj is " + xobj);
        System.out.println("yobj is " + yobj);
        // intValue() invoked. * op has precedence.
        System.out.println("xobj * yobj = " + xobj * yobj + "\n");
    }
}

Example 1: Program demonstrating autoboxing and auto­-unboxing.

You have witnessed autoboxing whenever you use the PrintWriter methods print(), println() and printf(). Consider the following:

System.out.println("The value of x is " + x + " and the value of y is " + y + ".");

The Java environment, in order to mix String with int was required to wrap the ints making them Integer objects. At that point it can call the toString() method to generate the String text necessary to mix with the other strings.

This is also the reason that the following piece of code produces something slightly unexpected:

int x = 10, y = 15;

System.out.println("The sum of x and y is " + x + y);

The output will be:

The sum of x and y is 1015

Now, seasoned programmers will spot the reason immediately. Did you spot it?

The reason this happens is:

  • First, the + operator is evaluated from left to right.
  • Second, the compiler assumes we are concatenating since the first + is with String and int.
  • Third, the compiler further extends this to the second + since it is still going to be String and int.

Important Note!
In the following two sections, we will introduce Vector and ArrayList. These classes have a lot in common but are not perfect replacements for each other. This is because they both implement the List interface but also have methods defined outside of that interface.

Implementing the List interface allows for easy substitution of one class for another as long as we use the interface’s methods.

This is the underpinning of understanding Inheritance and Polymorphism. Interfaces and subclasses introduce capabilities that allow objects to take many forms. After reading through this chapter, be sure to check out the final topic The instanceof Operator.


The Vector Class

As we mentioned, the Vector provides a more complete, dynamic approach to arrays. This is achievable since, under the hood, we are dealing with an array of objects. Objects imply references, which are essentially addresses. This further implies that we would be manipulating lists of references, not the data itself. In other words, if we were to add an item to or remove an item from the Vector, we are not rearranging the data, only the references to the data.

Recall that with arrays, we tend (but are not required) to populate the contents from beginning to end. And given enough programming structure, there would be nothing (except a lack of space!) to stop us from inserting or deleting anywhere in the array. (Seriously, make sure you read Chapter 9 – Managing Arrays.)

In addition, we needed to keep track of how many values were used in conjunction with the array’s length. This would be necessary if we wanted to know when to enlarge the array. You should be able to make the leap at this point that such an action to enlarge an array would require us to review our knowledge of array copy methods, specifically those involving creating a larger array at the same time or by consciously creating a larger array first and then performing a copy. (And that is just more work!)

Constructors and methods of the Vector class.
public Vector()
Create a vector of length 10 and no defined increment.
public Vector(int length)
Create a vector of specified length and no defined increment.
public Vector(int length, int increment)
Create a vector of specified length and increase length by increment when needed.
public boolean add(E e)
Add an object at the end of the Vector.
public void add(int index, E e)
Add an object at the index.
public int capacity()
Returns the current max capacity of the vector.
public Object clone()
Returns a copy of the vector.
public boolean contains(Object obj)
Returns true if obj is within the vector, otherwise returns false.
public E get(int index)
Returns element at index. Throws ArrayIndexOutOfBoundsException.
public int indexOf(Object obj)
Returns first occurrence of obj or -1 if not found.
public int indexOf(Object obj, int index)
Returns the first occurrence of obj starting at index or -1 if not found.
public boolean isEmpty()
Returns true if the vector is empty or false if it is not.
public int lastIndexOf(Object obj)
Returns last occurrence of obj or -1 if not found.
public int lastIndexOf(Object obj, int index)
Returns last occurrence of obj starting at index or -1 if not found.
public boolean remove(Object obj)
If exists, removes obj from vector and returns true; otherwise returns false.
public E remove(int index)
If element at index exists, it is removed. Throws ArrayIndexOutOfBoundsException.
public void removeAllElements()
Removes all elements from the vector.
public void setElementAt(Object obj, int index)
Sets the value of the element at index to obj. Throws ArrayIndexOutOfBoundException.
public int size()
Returns the number of elements contained in the vector.
public String toString()
Returns a string representation of the the vector.

Table 1: Various members of the Vector class.

Table 1 shows some basic members of the Vector class. Let us look at how to declare a variable of the Vector class:

Vector<String> rainbow = new Vector<>();

This statement declares a Vector reference variable called rainbow. It instantiates a new Vector object of 10 elements and assigns it to rainbow.

It is recommended that you include the reference type in angle brackets (< >) as demonstrated above since we intend to store Strings in the Vector. If you do not indicate this, you will receive a warning similar to:

Note: Program.java uses unchecked or unsafe operations. 
Note: Recompile with ­Xlint:unchecked for details.

The main concern is that the compiler will not check your objects as they are applied to certain methods. As a result, it would be possible to add an Integer object into the vector by simply writing:

rainbow.add(56);

And as we know, the autoboxing of 56 would turn it into an Integer object and would joyfully be added to the vector – not at all what we would like to have happen to our Vector of String data. With the reference type included, we would then receive a message similar to:

addElement(java.lang.String) in java.util.Vector<java.lang.String> cannot be applied to (int)

The Vector class is contained in the java.util package and the program in Example 2 demonstrates some basic actions on Vectors.

ColorVector.java
import java.util.Vector;

public class ColorVector {

    public static void main(String[] args) {

        Vector<String> rainbow = new Vector<>();
        int x, len;

        rainbow.add("Orange");
        rainbow.add("Yellow");
        System.out.println(rainbow);

        // forgot about Red!
        rainbow.add(0, "Red");
        System.out.println(rainbow);

        rainbow.add("Blue");
        rainbow.add("Fuchsia");
        rainbow.add("Indigo");
        rainbow.add("Violet");
        System.out.println(rainbow);

        // whoops, no Fuchsia in the rainbow
        rainbow.remove("Fuchsia");
        // forgot about Green!
        rainbow.add(3, "Green");
        System.out.println(rainbow);

        System.out.println();
        len = rainbow.size();
        for (x = 0; x < len; x++)
            System.out.println("Value at index " + x + " is " + rainbow.get(x));

        System.out.println();
        for (String s : rainbow)
            System.out.println(s);
    }
}

Example 2: Program demonstrating Vectors using the rainbow colors.

In Example 2, we use our previous declaration of rainbow and begin to add some elements to the Vector using the add() method. The program proceeds to alternate adding and printing the contents of the vector with the implied use of the toString() method, which is called whenever an object is to be displayed. (For a refresher see toString() in Chapter 8!)

The use of an overloaded version of add() and remove() was also employed to show the flexibility of vectors.

It is essential to see how the Vector automatically makes a hole for values inserted into the middle of the Vector and closes the gap left by a value that has been removed. In this example, we have even seen adding to the front, which pushes all of the existing values down one position.

A sample run of the program in Example 2 is shown below:

[Orange, Yellow]
[Red, Orange, Yellow]
[Red, Orange, Yellow, Blue, Fuchsia, Indigo, Violet]
[Red, Orange, Yellow, Green, Blue, Indigo, Violet]

Value at index 0 is Red
Value at index 1 is Orange
Value at index 2 is Yellow
Value at index 3 is Green
Value at index 4 is Blue
Value at index 5 is Indigo
Value at index 6 is Violet

Red
Orange
Yellow
Green
Blue
Indigo
Violet

The ArrayList Class

The ArrayList class is an alternative to Vector. It is often chosen due to lower overhead. The Vector is synchronized. That is, it is suitable for a multi-threaded application with multiple accessors. The synchronized nature is an attempt at guaranteeing that only one thread can modify an element. Uncontrolled modifications by multiple threads could spell certain disaster. When you know for certain that only one entity will use the data, ArrayList should be chosen over Vector.

Constructors and methods of the ArrayList class.
public ArrayList()
Create an ArrayList of length 10 and no defined increment.
public ArrayList(int length)
Create a vector of specified length and no defined increment.
public int size()
Returns the current number of objects in the ArrayList.
public boolean add(E e)
Add an object at the end of the ArrayList.
public void add(int index, E e)
Add an object at index.
public int indexOf(Object obj)
Returns first occurrence of obj or -1 if not found.
public E get(int index)
Returns element at index. Throws ArrayIndexOutOfBoundsException.
public boolean remove(Object obj)
If exists, removes obj from ArrayList and returns true; otherwise returns false.
public E remove(int index)
If element at index exists, it is removed. Throws ArrayIndexOutOfBoundsException.
public void removeAllElements()
Removes all elements from the ArrayList.
public void ensureCapacity(int minSize)
Guarantee capacity of at least minSize.

Table 2: Various members of the ArrayList class.

As you can see there are many methods of the ArrayList class that are also in the Vector class. This is due to the implementation of the List interface by both classes. It is generally an easy transition from one to the other if you use methods defined in the List interface.

One significant difference would be in the automatic growth of the object. Vector allows you to specify the automatic growth size through a constructor. ArrayList requires you to use the ensureCapacity() method if you want to get beyond the automatic growth of one (1).

Take the program in Example 1 and change the decalraion using Vector to ArrayList as shown below:

ArrayList<String> rainbow = new ArrayList<>();

The program still produces the same result. It just uses a different class.



Enumerations

Consider our set of primitive data types such as int, float, char, and double. These data types have values and operations that can be applied to them. We have also created more robust data types called classes. These classes used the primitive data types and other classes to make something more efficient and useful than a simple integer.

Java allows us to create data types and we can specify the exact set of values that the data type may possess. The data types are called enumerations and are identified by the use of the enum reserved word. A few examples of enumerations are shown below:

public enum Suit {Spades, Hearts, Clubs, Diamonds};

public enum Rank {Two, Three, Four, Five, Six, Seven, Eight,
            Nine, Ten, Jack, Queen, King, Ace};

Each value shown in the braces is an identifier, and each value is considered an enumeration constant. In addition, each enum is a special type of class, and each enumeration constant of this class are public static reference variables to objects of the enum type.

In other words, Spades is a reference variable of type Suit, and King is a reference variable of type Rank since both Suit and Rank are classes. So we can create declarations like the following:

Suit cardSuit;
Rank cardRank;

cardSuit = Suit.Hearts;
cardRank = Rank.King;

System.out.println(cardRank + " of " + cardSuit);

Since each enumeration constant is a reference variable and a public static member of the enumeration class, we can access the values with the dot operator, which assigned the object Hearts to cardSuit and King to cardRank. The output of the above is:

King of Hearts

Each enumeration constant in the enumeration type has a specific value. This is known as the ordinal value, and all ordinal values are implicitly final. The first enumeration constant is assigned the ordinal value 0, the next is 1, and so on. So for our Suit enumeration, Spades is 0, Hearts is 1, Clubs is 2, and Diamonds is 3.

Methods available for the enum type.
public final int compareTo(E obj)
Returns a negative, zero or positive value base on the ordinal of this object being less than, equal to or greater than the ordinal of obj, respectively.
public final boolean equals(Object obj)
Returns true if obj is equal to this enum constant.
public final int ordinal()
Returns the ordinal value of this enum constant.
public final String name()
Returns the name of this enum constant as declared.
public String toString()
Returns the string representation of an enum constant.
public static E[] values()
Automatically generated, implicitly declared method to return an array containing the constants of this enum.
public static E valueOf(String)
Automatically generated, implicitly declared method to return the enum constant with the specified name.

Table 3: Enumeration type methods.

Some enumeration methods are shown in Table 3. The following nested foreach loops show one method of iterating through the suits and ranks of a deck of cards:

for (Suit suit : Suit.values())
    for (Rank rank : Rank.values())
        System.out.println(rank + " of " + suit);

The variable suit is of enum type Suit and the values() method of the enum type is used to get the list of values to use in the foreach loop. Similarly, the rank variable is of enum type Rank, and the values() method is used to feed the inner for each loop.

As we stated earlier, an enum type is a special type of class, and the enum constants are reference variables to the objects of that enum type. We can immediately perceive data members, constructors, and methods within the enum type.

Therefore, let us set up some ground rules for the enum type:

  • Enumeration types are defined with enum and not class.
  • enum types are implicitly final since enum constants should not be modified.
  • enum constants are implicitly static.
  • You may declare reference variables of the enum type, but you cannot instantiate objects using the new operator.
  • Constructors are implicitly private.

In Example 3, we have an enumeration of United States coins: penny, nickel, dime, quarter, and half-dollar. Our main() method uses the Coins enum type as the reference type for Vector to create a pocket of between 1 and 10 random coins. Each coin in the pocket is randomized.

USCoins.java
import java.util.Vector;

public class USCoins {

    public enum Coins {

        Penny(0.01), Nickel(0.05), Dime(0.10), Quarter(0.25),
        HalfDollar(0.50);

        private final double value;

        /**
         * Contructor!
         *
         * @param value double value to be assigned to the coin
         */
        private Coins(double value) {
            this.value = value;
        }

        /**
         * Get the value of the coin.
         *
         * @return double value
         */
        public double getValue() {
            return value;
        }
    }

    public static void main(String[] args) {

        // Our pocket is a vector rather than an array.
        Vector<Coins> pocket = new Vector<>();
        int x, numCoins, randomCoin;

        // values() returns the enumeration as an array
        Coins[] definedCoins = Coins.values();
        double pocketValue = 0.0;

        // from 1 to 10 random coins in our pocket.
        numCoins = (int) (Math.random() * 10 + 1);
        System.out.printf("There are %d coins in our pocket.%n", numCoins);

        // add a random coin
        for (x = 0; x < numCoins; x++) {
            randomCoin = (int) (Math.random() * definedCoins.length);
            pocket.add(definedCoins[randomCoin]);
        }

        // Display the list of coins and calculate the pocket value
        System.out.println("Our pocket contains:\n" + pocket);
        for (Coins coin : pocket)
            pocketValue = pocketValue + coin.getValue();

        System.out.printf("%nPocket value is $%.2f.%n%n", pocketValue);
    }
}

Example 3: Program demonstrating enum type as a special class using U.S. coins.

The enumeration is designed to provide information about 5 possible coins whose names and values are clearly fixed and should never be changed. For example, a nickel is always called a nickel and is always worth 5 cents or .05 of one dollar. The enumeration type called Coins defines 5 enumeration constants: Penny, Nickel, Dime, Quarter and HalfDollar.

Recall from our discussion of user-defined classes that if no constructor is specified, then a default constructor is provided for you, and all instance variables are initialized to their type defaults. Since our Suit and Rank enumeration types had no such definitions, there were no instance variables to initialize, and there was a default constructor provided for the special enumeration type.

The stating of each enumeration constant (Penny, Nickel, etc.) is a call to a constructor (default or user-provided), which creates that constant as a final reference variable of an object of that enumeration type.

So Penny(0.01) is a call to the Coin(double value) constructor which creates Penny as a reference variable that points to an object of enum type Coins whose instance variable value is 0.01. The same thing is true for Nickel, Dime, Quarter, and HalfDollar for their respective values.

The main() method creates the pocket Vector, randomizes the number of coins, then for each coin to be placed in the pocket, picks a random coin from the list of possible coins and puts it into the pocket with add().

After the Vector is filled, we then display the coins in pocket, sum the values of the coins with a for each loop, and display the total. A few sample runs are shown below:

There are 10 coins in our pocket. 
Our pocket contains: 
[Nickel, Dime, Quarter, Penny, Penny, Penny, Nickel, HalfDollar, HalfDollar, Dime] 
Pocket value is $1.58. 
There are 5 coins in our pocket. 
Our pocket contains: 
[HalfDollar, HalfDollar, Dime, HalfDollar, HalfDollar] 
Pocket value is $2.10. 
There are 4 coins in our pocket. 
Our pocket contains: 
[Dime, Nickel, Nickel, Quarter] 
Pocket value is $0.45. 


Color Vector Part II

In the following example, we modify the ColorVector class from earlier to use an enumeration.

ColorVector2.java
import java.util.Vector;

public class ColorVector2 {

    enum Color {Red, Orange, Yellow, Green, Blue, Indigo, Violet}

    public static void main(String[] args) {

        Vector<Color> rainbow = new Vector<>();
        int x, len;

        rainbow.add(Color.Orange);
        rainbow.add(Color.Yellow);
        System.out.println(rainbow);

        // forgot about Red!
        rainbow.add(0, Color.Red);
        System.out.println(rainbow);

        rainbow.add(Color.Blue);
        rainbow.add(Color.Indigo);
        rainbow.add(Color.Violet);
        System.out.println(rainbow);

        // forgot about Green!
        rainbow.add(3, Color.Green);
        System.out.println(rainbow);

        System.out.println();
        len = rainbow.size();
        for (x = 0; x < len; x++)
            System.out.println("Value at index " + x + " is " + rainbow.get(x));

        System.out.println();
        for (String s : rainbow)
            System.out.println(s);
    }
}

Example 4: Color Vector using an enumeration.

In the previous version, we jokingly added Fuchsia and then removed it. In this example, we cannot do that since the Vector is now restricted to the newly introduced Color enumeration. If it does not appear in the list defined by Color, we cannot use it.

The great thing about this is it reduces and enforces the domain of values. With String as our data type, we could have put any color or type of potato or favorite TV shows in the Vector, and the compiler and runtime would allow it. Type-checking the Vector (<String>) made sure we could not mix data types in the Vector. Now, we have strict control over how the data looks.


The instanceof Operator

When working with various types, we often find situations where we must be more generic about handling data. This can be done in many ways, but we will introduce just a few here.

VectorObject.java
import java.util.Vector;
import java.util.ArrayList;
import java.util.List;

public class VectorObject {

    // A handful of enumerations
    public enum Coins {Penny, Nickel, Dime;}

    public enum Trees {Maple, Birch, Ash, Rowan;}

    public enum IceCream {RockyRoad, Vanilla, CrumbsAlongTheMohawk;}

    public static void main(String[] args) {

        List<Object> l;
        Vector<Object> v = new Vector<>();

        // l references the Vector. Although List is an interface,
        // it can be used to reference objects that implement it.
        l = v;
        
        // testing the instance type through polymorphism.
        if (l instanceof Vector)
            System.out.println("Vector");
        else if (l instanceof ArrayList)
            System.out.println("ArrayList");

        // We are invoking the add() method of the Vector through
        // late binding.
        l.add(Coins.Penny);
        l.add(Trees.Maple);
        l.add(IceCream.Vanilla);

        // Print the vector to show changes made with l.
        System.out.println(v);

        // Classify objects
        for (Object o : v)
            if (o instanceof Coins)
                System.out.println("The coin is " + o);
            else if (o instanceof Trees)
                System.out.println("The tree is " + o);
            else
                System.out.println("No idea!");
    }
}

Example 5a: Using List interface to demonstrate polymorphism and instanceof.

The output of Example 5a is below.

Vector
[Penny, Maple, Vanilla]
The coin is Penny
The tree is Maple
No idea!

In the next chapter, we will provide more detail on inheritance and polymorphism, but for now, we are content to demonstrate some of the versatility this provides. The details of the code provided in Example 5a are noted below.

  • We declared variables of type List and Vector (which implements List). A new Vector object is assigned to v.
  • We show how the List reference variable, l, can point to an instance of a class that implements List.
  • We demonstrate using instanceof to determine the type of List pointed to by l.
  • We use l to populate the Vector stored in v. This is possible due to late binding and invoking the correct method when needed.
  • instanceof to determine the kinds of objects in the Vector.

The flexibility of using an interface reference variable to point to various objects is particularly convenient. This is further demonstrated in Example 5b, where we use a method that uses a List parameter to allow for various types to be passed to it and take appropriate action based on the referenced type.

MethodObject.java
import java.util.Vector;
import java.util.ArrayList;
import java.util.List;
import java.util.LinkedList;

public class MethodObject {

    /**
     * Check the type of List
     *
     * @param list unbounded List type
     */
    public static void checkType(List list) {

        // use instanceof to determine type.
        if (list instanceof Vector)
            System.out.print("Vector has size " + list.size() + " and capacity " + ((Vector) list).capacity());
        else if (list instanceof ArrayList)
            System.out.print("ArrayList has size " + list.size() + " and unknown capacity");
        else
            System.out.print("Cannot use " + list.getClass());

        System.out.println(" with contents " + list);
    }

    public static void main(String[] args) {

        Vector v = new Vector<>(20);
        ArrayList a = new ArrayList<>(20);
        LinkedList l = new LinkedList<>();

        v.add(36);
        v.add(42);
        checkType(v);

        a.add(36);
        a.add(42);
        checkType(a);

        l.add(36);
        l.add(42);
        checkType(l);
    }
}

Example 5b: Using an interface on a method to

Vector has size 2 and capacity 20 with contents [36, 42]
ArrayList has size 2 and unknown capacity with contents [36, 42]
Cannot use class java.util.LinkedList with contents [36, 42]

In Example 5b, there are some specific details worth mentioning.

  • checkType() shows an argument of type List<?>, which is an unbounded wildcard type (see Wildcards in Chapter 11.)
  • We determine if the instance is a Vector. If true, it also uses a cast to be able to invoke the capacity() method, which ArrayList does not have.
  • We determine if the instance is an ArrayList. If true, it is only able to invoke size() since capacity() is not available.
  • We even printed the class we got and were unwilling to use. The getClass() method returns the String representation of the object pointed to by list.
  • List contents to the output immediately after the other details are determined.
  • In main(), we create three different objects that implement List.

Quiz

Given:

public enum Snack {Chips, Pretzels, Cookies, Granola_Bar, Candy};

Which of the following will display the values of the enumeration:

 
 
 
 

With auto-unboxing what happens when an Integer object is passed to a method expecting an int?

 
 
 
 

With auto-boxing and the use of println() the act of printing an int variable involves

 
 
 
 

Given:

public enum Domestic {Dog, Cat, Goldfish, Ferret, Parrot};

Which if the following will create an ArrayList to hold values from above?

 
 
 
 

Given:

public enum Pets {Dog, Cat, Goldfish, Ferret, Parrot};
Vector v = new Vector<>();

Which if the following will add Cat to the vector?

 
 
 
 

Loading ... Loading ...

Question 1 of 5

Loading


Exercises

Post navigation

❮ Previous Post: Chapter 9S – Sorting and Searching
Next Post: Chapter 11 – Inheritance and Polymorphism ❯

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Copyright © 2018 – 2025 Programming by Design.