视图—-通过使用视图可以获得其他实现了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");
}
}