HeapSort implementation
What comes to performance, it will degrade drastically if you pass a LinkedList (which implements java.util.List interface accepted in your heap sort): for such a list, get(int) operation runs not in constant time, but rather \$O(n)\$. In order to deal with it, check in your sort that the input list is not a linked list, and if it is, copy all the elements to an ArrayList, sort it, and load back to the input list.

The second point concerns the sifting algorithm. If the indices of the sifting operations are \$i_1, i_2, ..., i_n\$, you first swap \$i_1\$ with \$i_2\$, then \$i_2\$ with \$i_3\$ and so on until the element is in its proper place \$i_n\$. You can do better: save the element at \$i_1\$, then move \$i_2\$ to \$i_1\$, \$i_3\$ to \$i_2\$, and so on. Finally, just set the saved element at index \$i_n\$. This optimization does not improve the time complexity of heap sort, yet it reduces the constant factors hidden by the big-O notation.

The last, but not least: sometimes we do not need to sort the entire array/list. For this, it makes sense to code up a sorting routine, which can sort particular ranges. Then, in order to sort the entire array/list - as you do - you can just do:

sort(List&lt;T&gt; list) {
    sort(list, 0, list.size());
}