Eric’s right, but a lot of this also depends on how often you add objects to your arrays, what its length is (directly related to how much data it needs memory for), and also importantly, how you need to access it.
The reason why built-in arrays are always the fastest is that they are first of all contiguous in memory and second of all, once initialized, static in size. The contiguousness gives you access to individual elements in O(1)-time (constant time), because the system can simply add the index number to the start-address of the first element, and then retrieve that.
You get the same speedy random element-access with Lists, because they, too, store their elements contiguously in memory. But Lists don’t have a static size; they change their capacity dynamically based on the amount of elements added, and since the system can’t always be sure memory ahead of the current max is available when it wants to increase capacity, it sometimes has to move the list around around in memory when you add elements, to find a series of available memory addresses large enough to fit the new capacity in. This moving of a List’s elements is slow, and the same problem occurs if you remove elements from a generic List. Because its elements must always be contiguous in memory, it has to MOVE all elements ahead of the removed element one index down, which can take O(N) (linear time) in the worst case.
There are datastructures that do not store their data contiguously in memory. Examples of these are LinkedLists, Stacks or Queues, though there are many more. A LinkedList doesn’t reserve a contiguous row of memory addresses for its elements, but instead, for each element, stores pointers to the Previous and Next elements. This allows the runtime system to add and remove elements in O(1) (constant time), because no existing elements ever need to be moved around in memory to create room for new elements. This is highly efficient, but because these types of datastructures don’t store their elements contiguously, you lose the ability to look-up elements in constant time, which you had with a built-in array or a generic List. Now, because elements are scattered all over memory with pointers back and forth, the system has to run through all elements 0,1,2,3,4,5…n, following pointers to the next, and the next, etc, whenever you want to access element n. This is not particularly efficient.
So, what’s the conclusion? The conclusion is thus:
- If you know the precise amount of elements a collection will ever contain, use a built-in-array.
- If you don’t know the precise amount, but you know that you’re often going to require access to specific elements, use a List.
- If you don’t know the precise amount of elements, but you know that you’ll never need access to specific elements because you always traverse them all in a loop at a time, use a LinkedList.
- If you don’t know the precise amount, but you know you’ll only be traversing them all at a time, and your program excibits FIFO or LIFO behavior, use a Queue (FIFO) or a Stack (LIFO).
And, ABSOLUTELY MOST IMPORTANTLY:
If you know your collection won’t contain more than like 50-ish items anyway, the performance difference is often negligible, and you can safely disregard all of the above and choose whatever the hell you want. 