Unexpected behavior when creating Objects in a Vector

I have a situation where Objects in a Vector appear to be getting corrupted. The context is this: I obtain a ResultSet from a database, create a Vector of Strings for each row, and a Vector of these row vectors for the entire ResultSet. This is passed to a method where a POJO is created for each row. This method returns a Vector of these POJOs. In the Object constructor, a String array of initial values is created and also values are assigned to individual variables. Here is a snippet with the Object constructor

publicclass RefAuthorItem{

privatefinal String refKey;

private String authorKey, firstName, lastName, itemKey;

privateint authorPosition;

privateboolean isDeleted, isNew;

// Keep a copy of the original values

privatefinal String[] oldValues;

/**

* The constructor for the data object item.

*

* @param dataValsa String array of the data values

* @param isNewValboolean true if this is a new item, false if it is

* an existing item

*/

public RefAuthorItem(final String[] dataVals,finalboolean isNewVal){

oldValues = dataVals;

authorKey = dataVals[RefQueryBuilder.AUTH_NUM];

firstName = dataVals[RefQueryBuilder.AUTH_FIRST_NAME];

itemKey = dataVals[RefQueryBuilder.AUTH_PKEY];

lastName = dataVals[RefQueryBuilder.AUTH_LAST_NAME];

refKey = dataVals[RefQueryBuilder.AUTH_REF_FKEY];

isNew = isNewVal;

isDeleted =false;

// the author position integer value is used to sort the display

authorPosition =

Integer.parseInt(dataVals[RefQueryBuilder.AUTH_POS]);

}

It seems the oldValues[] values should be identical to the corresponding individual variable values. When the following code is used to create the objects, they are not.

finalboolean isNew = isNewVal;

Vector<RefAuthorItem> returnSet =new Vector<RefAuthorItem>();

final String queryString = QueryBuilder

.getRefQuery(keyString, tableName);

Vector<Vector> dataSet = QueryDB.getResultSet(queryString);

int columnTot = dataSet.firstElement().size();

String[] itemVals =new String[columnTot];

for (Iterator iter = dataSet.iterator(); iter.hasNext();){

Vector element = (Vector) iter.next();

for (int i = 0; i < columnTot; i++){

itemVals[i] = (String) element.get(i);

}

RefAuthorItem item =new RefAuthorItem(itemVals, isNew);

returnSet.add(item);

}

What happens is this. I returned four rows from the database and the oldValues[] array for each of the four corresponding objects contains the data from the fourth row. However, when I retrieve the corresponding individual values (e.g., authorLastName) from the Object, it is correct. I checked the object values (oldValues versus individual values retrieved via getters) right after the object is created (the line: RefAuthorItem item = new RefAuthorItem(itemVals, isNew);) and get the correct results. Also, results are correct when the itemVals constructor is moved within the loop, as below

int columnTot = dataSet.firstElement().size();

for (Iterator iter = dataSet.iterator(); iter.hasNext();){

Vector element = (Vector) iter.next();

String[] itemVals =new String[columnTot];

for (int i = 0; i < columnTot; i++){

itemVals[i] = (String) element.get(i);

}

RefAuthorItem item =new RefAuthorItem(itemVals, isNew);

returnSet.add(item);

}

There is a problem here. Am I missing a subtle Java issue with instantiating the String array within the loop? Or is there a problem with Vectors? Thanks!

[5128 byte] By [Michael.Schmidta] at [2007-11-26 13:10:54]
# 1
I haven't studied your code in detail yet, but if you're sitting there thinking there might be a bug in Vector or something, be assured you haven't found it. no offence meant!incidentally, why use Vector? bit old-fashioned these days. look at ArrayList
georgemca at 2007-7-7 17:25:43 > top of Java-index,Core,Core APIs...
# 2

Well you've found the solution.

In the non-working code you keep overrwriting the same itemVals[] array, which you are adding every time around the loop to the Vector, so all the elements are the same itemVal and they will have the same content, i.e. the most recent content.

This is a bug in your code, nothing to do with Vector.

ejpa at 2007-7-7 17:25:43 > top of Java-index,Core,Core APIs...
# 3

Dear ejp,

In the non-working code, I rewrite the itemVals[], create a new RefAuthorItem using the itemVals[] and repeat. I checked the RefAuthorItem immediately after it was created (with println()) and the oldValues and individual String values in the object are concordant. However, after the loop is completed (all RefAuthorItems are created and added to the Vector), the oldValues[] in the objects all have the values from the last row. The individual String variables in the object all have the correct value from the ResultSet row.

Michael.Schmidta at 2007-7-7 17:25:43 > top of Java-index,Core,Core APIs...
# 4
I agree, but that's the problem.You have the same itemVals object in every RefAuthorItem object.Each RefAuthorItem object's itemVal appears correct just after you create it, but you've just clobbered all the itemVal entries in the previous RefAuthorItems.
ejpa at 2007-7-7 17:25:43 > top of Java-index,Core,Core APIs...
# 5
Because in creating the RefAuthorItem, oldValues[] is passed the address of itemValues[], and then itemValues[] is subsequently changed in the loop? But then why are the individual variables in theRefAuthorItem objects, also assigned from itemValues[] not also "clobbered".
Michael.Schmidta at 2007-7-7 17:25:43 > top of Java-index,Core,Core APIs...
# 6

Because that's not the way it works!

String s1 = "s1";

String[] sa = new String[1];

sa[0] = s1;

sa[0] = "s2";

System.out.println(s1);

Would you expect this to print s1 or s2?

ejpa at 2007-7-7 17:25:43 > top of Java-index,Core,Core APIs...
# 7
Got it! Thanks ejp.
Michael.Schmidta at 2007-7-7 17:25:43 > top of Java-index,Core,Core APIs...