views:

472

answers:

6

I have a Vector that holds a number of objects. My code uses a loop to add objects to the Vector depending on certain conditions. My question is, when I add the object to the Vector, is the original object reference added to the vector or does the Vector make a new instance of the object and adds that?

For example, in the following code:

private Vector numbersToCalculate;
StringBuffer temp = new StringBuffer();

while(currentBuffer.length() > i) {
    //Some other code
    numbersToCalculate.add(temp);
    temp.setLength(0); //resets the temp StringBuffer
}

What I'm doing is adding the "temp" StringBuffer to the numbersToCalculate Vector. Should I be creating a new StringBuffer within the loop and adding that or will this code work? Thanks for the help!

Eric

+2  A: 

The Vector will store the reference you give it, it won't create its own copy of the object. So if you want the Vector to have buffers separate from the one you're continuing to use, as you said you'll need to create those separately by creating a new buffer instead of setting the old one's length to zero.

Off-topic side note: Vector is fairly out of date. you're probably better off with ArrayList (or one of the other classes implementing List, if you don't need an array backing it).

T.J. Crowder
Surely if you are replacing Vector with something newer it would be ArrayList? Why would you want to use a Map here?
DaveJohnston
@DaveJohnston: Thanks, brain failure there, it's been *that* long since I dealt with the old util classes. I was thinking of `Hashtable`. Fixed.
T.J. Crowder
ArrayList isn't synchronized and Vector is. If multiple threads are accessing the array, I would want to use Vector that ArrayList, correct? What disadvantages are there to Vector over ArrayList?
thechiman
@thechiman: No, I'd probably handle synchronization separately and explicitly (see the synchronization notes on ArrayList's overview[1]), use a synchronized version[2] via `syncrhonizedList`, or consider something from `java.util.concurrent` such as `CopyOnWriteArrayList`[3]. Links: [1] http://java.sun.com/javase/6/docs/api/java/util/ArrayList.html [2] http://java.sun.com/javase/6/docs/api/java/util/Collections.html#synchronizedList(java.util.List) [3] http://java.sun.com/javase/6/docs/api/java/util/concurrent/CopyOnWriteArrayList.html
T.J. Crowder
@thechiman (continuing): The thing with `Vector` and with the list you get back from` synchronizedList` is that each method call is *individually* synchronized. So if you do a series of method calls, you have to acquire the lock individually for each call in the series, which can be less than ideal. Doing your own synchronization puts you in direct control of the granularity with which you sync.
T.J. Crowder
+2  A: 

It uses the same object each time. You should add a temp = new StringBuffer(); to the end of your loop. (The result of your loop will be a Vector of pointers to the same single empty StringBuffer.)

froadie
+2  A: 

If you have to have an independent object added to the Vector, create a new one each time.

You're adding references to the vector. If the state of an object changes, then all references to it see the change.

duffymo
+1  A: 

Inserting an element into a collection does not, and can not, make a copy of an object, because Java has no formalized notion of a copy-constructor or operator overloading for user-defined types. That is, a general purpose collection can not know how to copy the contained objects.

Java's assignment operator always copies the pointer, never the contents, of a user-defined type.

meriton
+4  A: 

You need to create a new StringBuffer each time. Each item item in the Vector is just a pointer to the same StringBuffer object, so each time through the loop you are resetting the single instance of stringbuffer and adding the same reference to the Vector.

Just replace the temp.setLength(0); with temp = new StringBuffer();

DaveJohnston
+1  A: 

As most of the answers here say, a Vector stores references to objects of type Object. If you change the underlying Object each time you will end up with a Vector containing lots of references to one object, which now contains the last value you gave it.

Based on the name of your variables, I'm guessing you actually want to be storing numbers in your Vector.

In an ideal world you would just add object of type int into the Vector. Unfortunately, in Java an int is a 'primitive type', and Vector can only store objects of type Object. This means you can only put Integer objects into the Vector instead of int objects.

So your code will look something like:

// Put a number at index 0
Integer inputNumber = new Integer(7);
numbersToCalculate.add(0, inputNumber);

// Some time later read out the value at index 0
Object objFromVector = numbersToCalculate.elementAt(0);

// Cast the Object to an Integer
Integer numberToProcess = (Integer)objFromVector;

This code will throw an IllegalCastException if the Vector contains something that isn't an Integer object. If you are worried about that you can encompass it in a try catch statement.

In your example you will presumably want to just loop through all the numbers in the Vector. You also might want to be more prescriptive about what objects your Vector can contain (called 'Generics', which is similar to C templating). Here's what it might look like:

Vector<Integer> myVector = new Vector<Integer>();

// Add stuff to the Vector

for (Integer number : myVector)
{
    // Do stuff with the number
}

The foreach and Generics constructs were only added in Java SDK 1.5, so you can't use them if you want to run on an earlier Java SDK.

Dan J