14

I know you can't dynamically expand a normal array but is this a valid way of doing it?

public int size = 0;    
public String[] OrigArray = new String[size+1]; 

public void expand(){


            String[] tempArray = new String[size+1];    

            tempArray = (String[])OrigArray.clone();

            OrigArray = new String[size+1];

            OrigArray = (String[])tempArray.clone();    

            size++;         

    }

I'm aware of much better methods than trying to use a normal array but I'd like to figure this for just using a normal array first.

My desire is that it starts off with OrigArray being 0+1 (so 1) and when expand() is called the new tempArray is made that is the same size as the OrigArray and this then holds OrigArray while OrigArray is declared again with size+1 then the tempArray is copied back to the newly sized OrigArray. This makes sense to me, but I keep getting out of bound exception?

madth3
  • 7,275
  • 12
  • 50
  • 74
James MV
  • 8,569
  • 17
  • 65
  • 96
  • Yeah, although this may make sense to you, it doesn't to anyone else (including the compiler). – mre Dec 08 '11 at 22:57
  • OrigArray = (String[])tempArray.clone(); That doesn't do what you think it does. That tries to cram the tempArray into the original array. It's not replacing the OrigArray reference with one to tempArray. – Corbin Dec 08 '11 at 22:58

7 Answers7

19

The method does not change the value of OrigArray; all it does is store a clone of a clone in it, so in effect the value isn't changed.

I think what you want is this:

public void expand() {
    String[] newArray = new String[OrigArray.length + 1];
    System.arraycopy(OrigArray, 0, newArray, 0, OrigArray.length);

    //an alternative to using System.arraycopy would be a for-loop:
    // for(int i = 0; i < OrigArray.length; i++)
    //     newArray[i] = OrigArray[i];
    OrigArray = newArray;
}

This creates an array that has a size 1 greater than OrigArray, copies the content of OrigArray into it and assigns that array to OrigArray. Unless you want to remember how many times expand() has been called, there shouldn't be a reason to have the variable size.

EDIT: If what you really want is to know a way to sensibly implement the functionality you asked for, you can go with what @Óscar López said and use ArrayList.

G. Bach
  • 3,869
  • 2
  • 25
  • 46
6

What you're trying to accomplish by hand, it's pretty much what ArrayList does for you - use that class, instead.

Under the hood, ArrayList uses an Object[] for storing items, under a certain capacity constraint. When the array is filled (as new items are added), a new array with doubled size is created and all the items in the original array are copied in it. All this happens automatically, and it's transparent for the programmer.

Given that in the sample code you're storing an array of objects (Strings), there'll be little difference in performance if you use an ArrayList for storing them, so there's no real reason to reinvent the wheel!

Óscar López
  • 232,561
  • 37
  • 312
  • 386
2

No, that is not a valid way to do it. What you are doing is actually

First create a new larger array
Throw away the newly created array and copy the original array
Create year another new array with larger size
Throw away the newly created array and clone the already cloned array again

For non primitive types I think you want to use the ArrayList

However, if you want to build this for primitive types, this is how you would do it

public int size = 0;    
public int[] origArray = new int[size+1]; 

public void expand(){
    int[] tempArray = new int[size+1];    
    System.arrayCopy(origArray, 0, tempArray, 0, size);
    origArray = tempArray;
    size++;         
}

You probably want to hide the data behind accessors (get...() methods) and you do not want to just expand the array by one element at a time, creating and copying arrays is costly.

Roger Lindsjö
  • 11,330
  • 1
  • 42
  • 53
1

This:

OrigArray = new String[size+1];
OrigArray = (String[])tempArray.clone();

is essentially equivalent to just this:

OrigArray = (String[])tempArray.clone();

in that the second assignment completely supersedes the first. OrigArray will end up having the same size as tempArray, and therefore the same size that it originally had.

If you want to copy elements into an existing array, you have to either write a loop, or else use java.lang.System.arrayCopy(...) which handles the loop for you; but calling clone() on an array will always create a new array, so will not help.

ruakh
  • 175,680
  • 26
  • 273
  • 307
0

Your method won't work because clone() will just reassign the array to the original size. I would recommend using

System.arraycopy(OrigArray, 0, tempArray, 0, OrigArray.length);

instead.

Also, the most efficient way of doing this would be to use an ArrayList, since they implement practically the same thing, but clean up your code a lot.

The only problem is when you need to get a regular array of the value's type, then you would have to do this:

String[] asArr = new String[OrigArray.length];

for(int i = 0; i < OrigArray.length; i++)
  asArr[i] = OrigArray.get(i);

Here is the Javadoc for ArrayList:

http://docs.oracle.com/javase/1.4.2/docs/api/java/util/ArrayList.html

Jon Egeland
  • 12,470
  • 8
  • 47
  • 62
0

Take a look at System.arraycopy -- it copies one array to the other (you can also do this yourself in a loop, though arraycopy is a bit faster). So the general pattern is to create a new array that's bigger than the first, then copy the first's elements into the bigger one, and then update your field/variable to point to this new, bigger array.

yshavit
  • 42,327
  • 7
  • 87
  • 124
0

Constantly constructing and destructing objects in memory is costly and slow. I would write a class that stores a little extra space (maybe 3-5 extra items), similarly to how List works, and when querying the size only output the used spaces and only expand when exceeding this buffer space. This can greatly improve performance.