It's not that ad-hoc:
Arrays.java's sort method uses quicksort for arrays of primitives and merge sort for arrays of objects.
Why does Java's Arrays.sort method use two different sorting algorithms for different types?
Also, according to the docs:
For example, the algorithm used by sort(Object[]) does not have to be a mergesort, but it does have to be stable.
And another quote from the javadoc:
This sort is guaranteed to be stable: equal elements will not be
reordered as a result of the sort.
Implementation note: This implementation is a stable, adaptive,
iterative mergesort that requires far fewer than n lg(n) comparisons
when the input array is partially sorted, while offering the
performance of a traditional mergesort when the input array is
randomly ordered. If the input array is nearly sorted, the
implementation requires approximately n comparisons. Temporary storage
requirements vary from a small constant for nearly sorted input arrays
to n/2 object references for randomly ordered input arrays.
The implementation takes equal advantage of ascending and descending
order in its input array, and can take advantage of ascending and
descending order in different parts of the the same input array. It is
well-suited to merging two or more sorted arrays: simply concatenate
the arrays and sort the resulting array.
The implementation was adapted from Tim Peters's list sort for Python
( TimSort).