前言
印象中,Collections像是一個工具箱類,裏面有着集合類的各種幫助性質的方法,如reverse()等。而Collection是集合類的上級接口,繼承它的主要接口有List和Set,而List和Set的實現類也需要實現Collection定義的方法。
本文主要對Collections和Collection的區別進行介紹:
- Collections與Collection在類型上的區別
- Collections類型
- Collection類型
- Collections與Collection的常用方法
- Collections常用方法
- Collection常用方法
(若文章有不正之處,或難以理解的地方,請多多諒解,歡迎指正)
Collections與Collection在類型上的區別
Collections類型
前言提到,Collections是一個包含集合類的各種幫助性質方法的工具類,服務於Java的Collection類及其子類。
Collection類型
Collection是一個集合接口,提供了對集合對象進行基本操作的通用接口方法,有很多實現Collection接口的實現,如ArrayList、HashSet等。Collection接口的意義在於爲各種具體的集合提供了最基本的統一操作方式。
Collections與Collection的方法區別
Collections常用的方法
舉個簡單的栗子:
public static void main(String[] args){
ArrayList<Integer> list = new ArrayList<>();
list.add(3);
list.add(1);
list.add(2);
list.add(6);
list.add(5);
list.add(4);
}
1. sort(Collection c)
對集合進行排序
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null); //直接使用list本身的sort()方法來實現排序
}
//[3, 1, 2, 6, 5, 4]
Collections.sort(list); //[1, 2, 3, 4, 5, 6]
2. shuffle(Collection c)
對集合進行隨機排序
public static void shuffle(List<?> list, Random rnd) {
int size = list.size();
if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
for (int i=size; i>1; i--)
swap(list, i-1, rnd.nextInt(i)); //隨機交換
} else {
Object arr[] = list.toArray();
// Shuffle array 隨機交換生成數組
for (int i=size; i>1; i--)
swap(arr, i-1, rnd.nextInt(i));
ListIterator it = list.listIterator();
for (int i=0; i<arr.length; i++) {
it.next();
it.set(arr[i]);
}
}
}
//[1, 2, 3, 4, 5, 6]
Collections.shuffle(list); //[2, 6, 3, 5, 1, 4]
3. reverse()
反轉集合中元素的順序
public static void reverse(List<?> list) {
int size = list.size();
if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
swap(list, i, j); //反轉數組元素
} else {
//前後遍歷反轉數組
ListIterator fwd = list.listIterator();
ListIterator rev = list.listIterator(size);
for (int i=0, mid=list.size()>>1; i<mid; i++) {
Object tmp = fwd.next();
fwd.set(rev.previous());
rev.set(tmp);
}
}
}
//[3, 1, 2, 6, 5, 4]
Collections.reverse(list); //[4, 5, 6, 2, 1, 3]
4. fill(List list, Object o)
用對象o替換集合list中的所有元素
public static <T> void fill(List<? super T> list, T obj) {
int size = list.size();
//遍歷集合,替換集合中的所有元素
if (size < FILL_THRESHOLD || list instanceof RandomAccess) {
for (int i=0; i<size; i++)
list.set(i, obj);
} else {
ListIterator<? super T> itr = list.listIterator();
for (int i=0; i<size; i++) {
itr.next();
itr.set(obj);
}
}
}
//[3, 1, 2, 6, 5, 4]
Collections.fill(list, 0); //[0, 0, 0, 0, 0, 0]
5. copy(List m, List n)
將集合n中的元素全部複製到m中,並且覆蓋相應索引的元素
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
int srcSize = src.size();
if (srcSize > dest.size())
throw new IndexOutOfBoundsException("Source does not fit in dest");
if (srcSize < COPY_THRESHOLD ||
(src instanceof RandomAccess && dest instanceof RandomAccess)) {
for (int i=0; i<srcSize; i++) //將數組src中的數組複製到dest中
dest.set(i, src.get(i));
} else {
//遍歷兩個集合,將一個集合的數據複製到另一個數組中
ListIterator<? super T> di=dest.listIterator();
ListIterator<? extends T> si=src.listIterator();
for (int i=0; i<srcSize; i++) {
di.next();
di.set(si.next());
}
}
}
//[3, 1, 2, 6, 5, 4]
List<Integer> list2 = new ArrayList<>();
list2.add(-100);
list2.add(-200);
list2.add(-300);
list2.add(-400);
list2.add(-500);
list2.add(-600);
Collections.copy(list, list2); //[-100, -200, -300, -400, -500, -600]
6. rotate(List list, int m)
集合中的元素向後移動m個位置,在後面被遮蓋的元素循環到前面來
public static void rotate(List<?> list, int distance) {
if (list instanceof RandomAccess || list.size() < ROTATE_THRESHOLD)
rotate1(list, distance);
else
rotate2(list, distance);
}
private static <T> void rotate1(List<T> list, int distance) {
int size = list.size();
if (size == 0)
return;
//此處主要是對distance值進行處理
distance = distance % size;
if (distance < 0)
distance += size;
if (distance == 0)
return;
//因爲可能會出現後面的數據被覆蓋的可能,所以需要多一個do...while...來進行處理
for (int cycleStart = 0, nMoved = 0; nMoved != size; cycleStart++) {
T displaced = list.get(cycleStart);
int i = cycleStart;
do {
i += distance;
if (i >= size)
i -= size;
displaced = list.set(i, displaced);
nMoved ++;
} while (i != cycleStart);
}
}
private static void rotate2(List<?> list, int distance) {
int size = list.size();
if (size == 0)
return;
int mid = -distance % size;
if (mid < 0)
mid += size;
if (mid == 0)
return;
//根據distance與size的關係,將集合分成兩段,分別進行反轉,然後再將整個集合元素順序進行反轉
reverse(list.subList(0, mid));
reverse(list.subList(mid, size));
reverse(list);
}
//[3, 1, 2, 6, 5, 4]
Collections.rotate(list, 3); //[6, 5, 4, 3, 1, 2]
7. max(Collection), max(Collection, Comparator)/min(Collection), min(Collection, Comparator)
前者採用Collection內置的自然比較法,後者採用Comparator制定的比較規則進行比較
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) {
Iterator<? extends T> i = coll.iterator();
T candidate = i.next();
//遍歷集合,選出最大值
while (i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;
}
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll) {
Iterator<? extends T> i = coll.iterator();
T candidate = i.next();
//遍歷集合,選出最小值
while (i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) < 0)
candidate = next;
}
return candidate;
}
//[3, 1, 2, 6, 5, 4]
System.out.println(Collections.max(list)); //6
System.out.println(Collections.min(list)); //1
8. indexOfSubList(List list, List subList)
查找subList在list中首次出現的位置索引
public static int indexOfSubList(List<?> source, List<?> target) {
int sourceSize = source.size();
int targetSize = target.size();
//遍歷source的次數,無需全部遍歷
int maxCandidate = sourceSize - targetSize;
if (sourceSize < INDEXOFSUBLIST_THRESHOLD ||
(source instanceof RandomAccess&&target instanceof RandomAccess)) {
nextCand:
//遍歷source集合
for (int candidate = 0; candidate <= maxCandidate; candidate++) {
//target集合中的元素與sourse集合中的元素進行比較
for (int i=0, j=candidate; i<targetSize; i++, j++)
if (!eq(target.get(i), source.get(j)))
continue nextCand; // Element mismatch, try next cand
return candidate; // All elements of candidate matched target
}
} else { // Iterator version of above algorithm
ListIterator<?> si = source.listIterator();
nextCand:
//依然是遍歷兩個集合
for (int candidate = 0; candidate <= maxCandidate; candidate++) {
ListIterator<?> ti = target.listIterator();
for (int i=0; i<targetSize; i++) {
if (!eq(ti.next(), si.next())) {
// Back up source iterator to next candidate
//如果ti.next()與si.next()不相等,則需要將迭代器指針位置移回source集合的首位
for (int j=0; j<i; j++)
si.previous();
continue nextCand;
}
}
return candidate;
}
}
return -1; // No candidate matched the target
}
//[3, 1, 2, 6, 5, 4]
List<Integer> list2 = new ArrayList<>();
list2.add(2);
list2.add(6);
System.out.println(Collections.indexOfSubList(list, list2)); //2
9. replaceAll(List list, Object old, Object new)
替換批定元素爲某元素,若要替換的值存在則返回true,反之返回false
public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal) {
boolean result = false;
int size = list.size();
//遍歷集合,找到要替換的元素後進行替換操作
if (size < REPLACEALL_THRESHOLD || list instanceof RandomAccess) {
//如果替換的元素是null,則需要單獨處理
if (oldVal==null) {
for (int i=0; i<size; i++) {
if (list.get(i)==null) {
list.set(i, newVal);
result = true;
}
}
} else {
for (int i=0; i<size; i++) {
if (oldVal.equals(list.get(i))) {
list.set(i, newVal);
result = true;
}
}
}
} else {
ListIterator<T> itr=list.listIterator();
//同上
if (oldVal==null) {
for (int i=0; i<size; i++) {
if (itr.next()==null) {
itr.set(newVal);
result = true;
}
}
} else {
for (int i=0; i<size; i++) {
if (oldVal.equals(itr.next())) {
itr.set(newVal);
result = true;
}
}
}
}
return result;
}
//[3, 1, 2, 6, 5, 4]
Collections.replaceAll(list, 2, 200); //[3, 1, 200, 6, 5, 4]
10. swap(List list, int i, int j)
交換集合中指定元素索引的位置
public static void swap(List<?> list, int i, int j) {
final List l = list;
l.set(i, l.set(j, l.get(i))); //當使用l.set()方法時會返回替換位置原先的數據
}
//[3, 1, 2, 6, 5, 4]
Collections.swap(list, 2, 5); //[3, 1, 4, 6, 5, 2]
Collection的方法
Collection是集合接口,因子類如ArrayList、LinkedList、HashSet等的底層結構不同,所以其方法實現在各子類也是有所不同,此處不進行贅述,有興趣的朋友可以看筆者之前文章,或者關注筆者,筆者後續還會寫Java集合系列的文章。
結語
其實Collections與Collection最本質的區別就在於,一個是類,一個是接口;而且它們之間的關係是,一個是工具,一個是被操作者。
本文主要對final關鍵字進行介紹,如果本文對你有幫助,請給一個贊吧,這會是我最大的動力~
參考資料