java集合---檢視與包裝器
檢視—-通過使用檢視可以獲得其他實現了Collection與Map介面的物件。對映類的keySet就是這樣一個例項。初看起來,好像這個方法建立了一個新集,並將對映中的所有鍵都填進去,然後返回這個集。但是,事實並非如此。取而代之的是:keySet方法返回一個實現了Set介面的類物件,這個類的方法對原對映進行操作。這種集合就是檢視。
輕量級集合包裝器
Arrays類的靜態方法asList將返回一個包裝了普通java陣列的List包裝器,這個方法可以將陣列傳遞給一個期望得到的列表或集合引數中:
package view;
import java.util.Arrays;
import java.util .Collections;
import java.util.List;
public class Testview01 {
public static void main(String[] args) {
String[] str = new String[10];
//這裡返回的物件不是一個ArrayList。它是一個檢視物件,帶有訪問底層陣列的get和set方法
List<String> list = Arrays.asList(str);
list.set(2, "aaa");
System.out .println(list.get(2));
//改變陣列大小的所有方法,例如add、remove方法等,都會丟擲Unsupported OperationException異常
//list.add("aaa");
System.out.println(list.size());
System.out.println("----------我是分割線----------");
//asList可以接受可變數目的引數
List<String> names = Arrays.asList("aa", "bb" , "cc");
System.out.println(names);
//names.add("aaaaaa");同樣會報錯,原因同上
System.out.println(names.size());
System.out.println("----------我是分割線----------");
List<String> set = Collections.nCopies(100, "default");
//實際上在這裡只進行了一次賦值操作,詳見jdk
System.out.println(set.get(0) == set.get(10));
}
}
這是關於Collections.nCopies()方法的jdk原始碼截圖,這裡充分說明了它只進行了一次賦值。
區分Collections類和Collection介面
Collections類包含了很多實用的方法,這些方法的引數和返回值都是集合;不要與Collection介面混淆。
//這個方法將返回一個檢視物件。這個物件實現了Set介面,返回的物件實現了一個不可修改的單元素集,
//而不需要付出建立資料結構的開銷
Set singleton = Collections.singleton(names);
for(Object sets : singleton) {
System.out.println(sets);
子範圍
package view;
import java.util.Arrays;
import java.util.List;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
public class TestView02 {
public static void main(String[] args) {
String[] str = new String[]{"aa", "dd", "ff", "cc", "qq", "bb"};
List<String> list = Arrays.asList(str);
System.out.println(list);
List group = list.subList(2, 5);
System.out.println(group);
System.out.println("----------我是分割線----------");
SortedSet<String> set = new TreeSet<String>(list);
SortedSet<String> subset = set.subSet("aa", "dd");//大於aa小於dd不包含dd
System.out.println(subset);
subset.clear();//刪除選中的項,並且直接反應在原對映中
System.out.println(set);
System.out.println("----------我是分割線----------");
SortedMap<Integer, String> map = new TreeMap<Integer, String>();
map.put(1, "ff");
map.put(2, "aa");
map.put(3, "gg");
map.put(4, "ee");
map.put(5, "cc");
System.out.println(map);
SortedMap<Integer, String> submap = map.subMap(2, 4);
System.out.println(submap);
submap.clear();
System.out.println(map);
}
}
不可修改檢視
Collections 還有幾個方法, 用於產生集合的不可修改檢視。 這些檢視對現有集合增加了一個執行時的檢查。 如果發現試圖對集合進行修改, 就丟擲一個異常, 同時這個集合將保持未修改狀態;
(再次提醒:注意區分 Collection 和 Collections)
可以使用下列8種方法獲得不可修改檢視:
Collections.unmodifiableCollection
Collections.unmodifiableList
Collections.unmodifiableSet
Collections.unmodifiableSortedSet
Collections.unmodifiableMap
Collections.unmodifiableSortedMap
Collections.unmodifiableNavigableSet
Collections.unmodifianleNavigableMap
每個方法都定義於一個介面。如, Collections.unmodifiableList 與 ArrayList、LinkedList 或者任何實現了 List介面的其他類一起協同工作;
package view;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
public class TestView03 {
public static void main(String[] args) {
List<String> list = Collections.nCopies(5, "default");
List view = Collections.unmodifiableList(list);//該方法獲取不可修改的檢視
System.out.println(view.get(0));
view.add("aaa");//報錯,獲取的是不可修改檢視
System.out.println("----------我是分割線----------");
List<String> staff = new LinkedList<String>();
lookAt(Collections.unmodifiableList(staff));
}
}
Collections.unmodifiableList 方法返回一個實現List介面的類物件。當然,lookAt方法 可以呼叫 List 介面中的所有方法, 而不只是訪問器。但是所有的更改器方法,已經被重新定義為 丟擲一個 UnsuportedOperationException 異常,而不是 將呼叫傳遞給底層集合;
注意:
不可修改檢視並不是聚合本身不可修改,只是無法通過其投影出來的檢視修改原集合。仍然可以實用集合的原始引用修改原集合。
由於檢視只是包裝了介面而不是實際的集合物件,所以只能訪問介面中定義的方法。例如,LinkedList類有一些常用的方法,addFirst和addLast,他們都不是List介面方法,不能通過不可修改檢視訪問。
同步檢視
如果由多個執行緒訪問集合,就必須確保集不會被意外的破壞。類庫設計者使用檢視機制來確保常規集合的執行緒安全,而不是實現執行緒安全的集合。例如,Collections類的靜態synchronizedMap可以將任何一個對映錶轉換成具有同步訪問方法的Map:
Map<String, Employee> map = Collections.synchronizedMap(new HashMap<String, Employee>())
受查檢視
package view;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
public class TestView04 {
public static void main(String[] args) {
ArrayList<String> str = new ArrayList<String>();
ArrayList string = str;
string.add(new Date());//到這裡並沒有發現新增的型別不符
Date date = (Date)string.get(0);
System.out.println(date);
/*String s = (String) string.get(0);//這裡檢測到型別不匹配
System.out.println(s);*/
System.out.println("----------我是分割線----------");
ArrayList<String> str2 = new ArrayList<String>();
List<String> safe = Collections.checkedList(str2, String.class);
List string02 = safe;
string02.add(new Date());//編譯器沒有檢測到這裡的add異常
System.out.println("ok");
}
}