Bom, obviamente não vou questionar por que é que você usa um ArrayList em vez de um TreeSet, porque provavelmente você quer também elementos com a mesma chave, o que o TreeSet não aceita (ele não aceita mais de um elemento com a mesma chave, como um MultiSet do C++).
Então você simplesmente poderia fazer algo assim:
EDIT - (Implementação da sugestão que o ViniGodoy deu acima.)
import java.util.*;
class Pair<T, U> {
public T first;
public U second;
public Pair(T t, U u) { first = t; second = u; }
public String toString() { return "(" + first + "," + second + ")"; }
}
class TesteIndices {
public static void main (String[] args) {
List<Integer> desordenado = new ArrayList<Integer>();
desordenado.addAll (Arrays.asList (new Integer[]{
3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7
}));
System.out.println ("Array original:");
System.out.println (desordenado);
// Vamos criar um array contendo os elementos do array original, e
// os índices desses elementos. Então vamos ordenar esse array
// segundo os valores dos elementos. Para saber a posição original,
// basta pegar os índices.
List<Pair<Integer, Integer>> ordenadoEIndice = new ArrayList<Pair<Integer,Integer>>();
for (int i = 0; i < desordenado.size(); ++i) {
ordenadoEIndice.add (new Pair<Integer, Integer> (desordenado.get(i), i));
}
System.out.println ("Antes da ordenação:");
System.out.println (ordenadoEIndice);
Collections.sort (ordenadoEIndice, new Comparator<Pair<Integer, Integer>>() {
public int compare (Pair<Integer, Integer> p1, Pair<Integer, Integer> p2) {
return p1.first.compareTo (p2.first);
}
});
System.out.println ("Depois da ordenação:");
System.out.println (ordenadoEIndice);
for (int i = 0; i < desordenado.size(); ++i) {
System.out.printf ("A posição original do elemento [%d] = %d era %d%n",
i, ordenadoEIndice.get(i).first, ordenadoEIndice.get(i).second);
}
}
}
Estou dando um exemplo com Integer, mas obviamente você pode usar outro tipo de objeto.