A little while ago I talked about Vectors but I didn't cover as much about them as I wanted too. I was completely blind as to how the structure truly works and why it isn't always the best choice.
Generics and Vectors
In the previous tutorial I showed how the Vector can hold objects but there is a bit more to it than that. The Vector class is a generic class which means you can indicate what type of data the Vector can hold. The default value is of type Object.
Since the default value is of type Object, it can hold any type of data. Why? In Java, all classes are subclasses of type Object. If you declare a Vector to hold objects of type Object it can hold data of type Object and anything that is a subclass of Object.
In Netbeans, if I press Ctrl-B I can see the code that creates the Vector object. I've learned so much reading the code in the Vector class.
Let us look at the class declaration of the Vector.
public class Vector<E>
The <E> indicates that the Vector is a generic class. When you declare an instance of the class you call the constructor but you also specify the type of data the vector holds.
Vector<Object> v = new Vector<Object>();
The above code creates a Vector object that holds Objects. This is the same as writing
Vector v = new Vector();
However, if I want a Vector that just holds Integer object, I would declare it as follows:
Vector<Integer> v = new Vector<Integer>();
You can change the data type in the angle brackets to whatever you want. It has to be a Object though. It cannot be a primitive data type.
Why use generics?
Generics enforce that the structure only holds data of a certain type. If you try to add something that is not of the declared type then the program will fail. It also eliminates the need to use typecasting to get the data out from the vector. If you declare a vector to be of type Object you have to use typecasting to get the correct data type.
Vector v = new Vector(); v.add(new Integer(6)); v.add(new String("test")); System.out.println((Integer)v.get(0)); System.out.println((String)v.get(1));
This is messy and more prone to errors. If you declare it to be more generic you do not have to make the type casts. The above lines return a value of type Object which has to be converted to the appropriate type.
Vector<Integer> v = new Vector<Integer>(); v.add(6); v.add(8); System.out.println(v.get(0)); System.out.println(v.get(1));
Since the method is a generic method, the return type is whatever type the Vector was declared as. The above 2 lines return a value of type Integer instead of type Object. The idea of generics is very similar to the idea of templates in C++. I haven't explained very much (if anything) about how generics actually work but it can make your code a lot easier to follow and helps to prevent silly errors.
Deleting items from the vector is as simple as calling the remove method and passing the index to delete at. As simple as this is, this isn't the most efficient operation when deleting items from the middle of the list.
Looking at how the Vector works we can determine that it is inefficient at inserting and deleting items in the structure. Why? When a vector is created it has a certain size. When an item is added at the end of the structure, the array has to be resized.
If the array has 450 items in it and an item is deleted at the end, we have to copy 449 items into a new array.
If this occurs often then the program has to constantly maintain the vector which results in lower performance.
Now imagine if an item is added at position 5 in the vector. The vector has to be resized and everything after position 5 has to be moved over to make room for the new item.
If you need to remove or add items in random positions in the list then the Vector is not the most efficient structure and you should be using a Linked List structure instead.
However, when you need an array structure that grows this is a great structure to use. It is used in Java's implementation of the Stack.
Hope this helps explain more about how the Vector works.