Namely, the amortised time complexity of dynamic lists.
Amortised analysis treats operations not as single events but looks at the time complexity over the span of many operations (through something called "Accounting"). An initial "investment" of array over-allocation will be amortised by inserting, but only over time. Inserting into an ArrayList will be in O(1) given enough insert operations.
Essentially, you over-allocate in order to save time. You're trading time complexity for space complexity.
A really good explanation on amortised analysis can be found here on Wikipedia, which explicitly treats ArrayList:
https://en.wikipedia.org/wiki/Amortized_analysis#Dynamic_Arr...
As always, a look into the source code of your language of choice helps. In Python, a list object over-allocates using a very peculiar, but finely tuned formula: https://github.com/python/cpython/blob/09dc3ec1713c677f71ba7...