在使用jdk1.7后发现,部分使用排序的列表变了。然后就可劲的找原因。最后发现:
首先进入Collection.sort方法
public static <T extends Comparable<? super T>> void sort(List<T> list) {
Object[] a = list.toArray();
Arrays.sort(a);
ListIterator<T> i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}
本质就是对数组进行排序然后输出。
再进入Arrays.sort()方法
public static void sort(Object[] a) {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a);
else
ComparableTimSort.sort(a);
}
看到这,其实也里看到点东西了,哈哈userRequested,再点进去
static final class LegacyMergeSort {
private static final boolean userRequested =
java.security.AccessController.doPrivileged(
new sun.security.action.GetBooleanAction(
"java.util.Arrays.useLegacyMergeSort")).booleanValue();
}
原来如此,在JVM中配置-Djava.util.Arrays.useLegacyMergeSort=true ,就可以使用传统的归并排序了。
到此为止,已经解决为什么JDK1.7的排序会与JDK1.6不致的问题的。下面我们来深入的看下这两个排序方式的迥异:
legacyMergeSort()核心实现
private static void mergeSort(Object[] src,
Object[] dest,
int low,
int high,
int off) {
int length = high - low;
// Insertion sort on smallest arrays
if (length < INSERTIONSORT_THRESHOLD) {
for (int i=low; i<high; i++)
for (int j=i; j>low &&
((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
swap(dest, j, j-1);
return;
}
// Recursively sort halves of dest into src
int destLow = low;
int destHigh = high;
low += off;
high += off;
int mid = (low + high) >>> 1;
mergeSort(dest, src, low, mid, -off);
mergeSort(dest, src, mid, high, -off);
// If list is already sorted, just copy from src to dest. This is an
// optimization that results in faster sorts for nearly ordered lists.
if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {
System.arraycopy(src, low, dest, destLow, length);
return;
}
// Merge sorted halves (now in src) into dest
for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)
dest[i] = src[p++];
else
dest[i] = src[q++];
}
}
排序个数小于7,直接使用插入排序,时间复杂度为O(n2),适用于小数据排序。其它部分典型的归并排序实现法。不过人家写的确实高效率 int mid = (low + high) >>> 1; 给我们肯定直接就成了int mid=(low+high)/2;
ComparableTimSort.sort(a)核心实现
rangeCheck(a.length, lo, hi);
int nRemaining = hi - lo;
if (nRemaining < 2)
return; // Arrays of size 0 and 1 are always sorted
// If array is small, do a "mini-TimSort" with no merges
if (nRemaining < MIN_MERGE) {
int initRunLen = countRunAndMakeAscending(a, lo, hi);
binarySort(a, lo, hi, lo + initRunLen);
return;
}
/**
* March over the array once, left to right, finding natural runs,
* extending short natural runs to minRun elements, and merging runs
* to maintain stack invariant.
*/
ComparableTimSort ts = new ComparableTimSort(a);
int minRun = minRunLength(nRemaining);
do {
// Identify next run
int runLen = countRunAndMakeAscending(a, lo, hi);
// If run is short, extend to min(minRun, nRemaining)
if (runLen < minRun) {
int force = nRemaining <= minRun ? nRemaining : minRun;
binarySort(a, lo, lo + force, lo + runLen);
runLen = force;
}
// Push run onto pending-run stack, and maybe merge
ts.pushRun(lo, runLen);
ts.mergeCollapse();
// Advance to find next run
lo += runLen;
nRemaining -= runLen;
} while (nRemaining != 0);
// Merge all remaining runs to complete sort
assert lo == hi;
ts.mergeForceCollapse();
assert ts.stackSize == 1;
ComparableTimSort来源于GOOGLE,详见下文
两个对象直接比如定义Comparator
public double compare(Object o1, Object o2) {
ComparaContainer tr1 = (ComparaContainer) o1;
ComparaContainer tr2 = (ComparaContainer) o2;
if (tr1.getCompareValue() < tr2.getCompareValue()) {
return (tr1.getCompareValue()-tr2.getCompareValue());
} else if (tr1.getCompareValue() == tr2.getCompareValue()) {
return tr1.getSecondValue() <= tr2.getSecondValue() ? 0 : 1;
} else {
return 1;
}
}
由于1.7改得更为严谨不能直接使用-1,0,1来表示小于、等于、大于
得改用a-b
如下所示
public int compare(Object o1, Object o2) {
ComparaContainer tr1 = (ComparaContainer) o1;
ComparaContainer tr2 = (ComparaContainer) o2;
double m = tr1.getCompareValue()-tr2.getCompareValue();
if (tr1.getCompareValue() < tr2.getCompareValue()) {
return (int)m;
} else if (tr1.getCompareValue() == tr2.getCompareValue()) {
m = tr1.getSecondValue()- tr2.getSecondValue();
return (int)m;
} else {
return (int)m;
}
}
或者最简单的是将原来return 0;的改成return -1;