Collection 和 Map

xiaoxiao2021-02-27  243

一.

Collection 和 Map

java.util.Collection[接口 接口是描述 Set 和 List 集合类型的根接口,其中定义了有关集合操作的普遍性方法] –java.util.List[接口] —java.util.ArrayList[实现类] —java.util.LinkedList[实现类] —java.util.Vector[实现类] —–java.util.Stack[实现类] –java.util.Set[接口] —java.util.HashSet[实现类] —–LinkedHashSet[实现类] —java.util.SortedSet[子接口] —–java.util.TreeSet[实现类] –java.util.Queue[接口 不常用] java.util.Map[接口] –HashTable[实现类(同步,不允许使用 null 键值)] –AbstractMap[实现类] —–java.util.SortedMap[子接口] —–java.util.TreeMap[实现类] —–java.util.HashMap[实现类(除了不同步和允许空键/值之外,Hash table大致相同)] ——LinkedHashMap[实现类] –java.util.WeakHashMap[实现类]

1.0 Collection

Collection 是最基本的集合接口,一个 Collection 代表一组 Object ,即 Collection 的元素(Elements)。一些 Collection 允许相同的元素而另一些不行。一些能排序而另一些不行。Java SKD 不提供直接继承自 Collection 的类,Java SDK 提供的类都是继承自 Collection 的“子接口”如 List 和 Set。 所有实现 Collection 接口的类都必须提供两个标准的构造函数:无参数的构造函数用于创建一个空的 Collection ,有一个 Collection 参数的构造函数用与创建一个新的 Collection ,这个新的 Collection 与传入的 Collection 有相同的元素。后一个构造函数允许用户复制一个 Collection。

1.1 Iterator 迭代器

迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。  Java中的Iterator功能比较简单,并且只能单向移动:

  (1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。   (2) 使用next()获得序列中的下一个元素。   (3) 使用hasNext()检查序列中是否还有元素。   (4) 使用remove()将迭代器新返回的元素删除。   

Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。 如何遍历 Collection 中的每一个元素呢? 无论 Collection 的实际类型如何,他都支持一个 iterator()的方法,该方法返回一个迭代子( 即迭代器,将所有集合的遍历做一个总的抽象。),使用该迭代子即可逐一访问 Collection 中每一个元素。经典用法: Iterator it = collection.iterator();//获得一个迭代器 whileit.hasNext()){ Object obj = it.next();//得到下一个元素 }

1.2 由 Collection 接口派生的两个接口是 List 和 Set

1.2.1List 接口

List(interface): 次序是List最重要的特点是有序的;它确保维护元素特定的顺序。使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在 List 中的位置,类似于数组下标)来访问 List 中的元素,这类似于 java 中的数组。List为Collection添加了许多方法,使得能够向List中间插入与移除元素(只推荐LinkedList使用)。一个List可以生成ListIterator,使用它可以从两个方向遍历List,也可以从List中间插入和删除元素List允许有相同的元素。除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个ListIterator接口,和标准的Iterator 接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,还能向前或向后遍历。 实现List接口的常用类有LinkedList,ArrayList,Vector和Stack。 ArrayList 和 Vector 都有一个初始的容量大小,当存储存储他们里面的元素的个数超过了容量时,就需要增加 ArrayList 和 Vector 的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,ArrayList 和 List 都可以设置初始空间大小,Vector还可以设置增长空间的大小,而 ArrayList 没有提供设置增长空间的方法。 Vector提供indexOf(obj, start)接口,ArrayList没有。indexOf 方法返回一个整数值,指出 String 对象内子字符串的开始位置。如果没有找到子字符串,则返回 -1。 Vector 是线程安全的,也就是说它的方法之间是线程同步的,而 ArrayList 是线程不安全的,它的方法之间是线程不同步的。如果只有一个线程会访问到集合,那最好是使用 Array List ,因为它不考虑线程安全,效率会高些;如果有多个线程会访问到集合,那最好还是使用Vector,因为不需要我们自己再去考虑和编写线程安全代码。 ArrayList: 是线程不安全的,由数组实现的List。它允许对元素进行快速随机访问,但是向List中间插入与移除元素的速度很慢。ListIterator只应该用来由后向前遍历ArrayList,而不是用来插入和删除元素,因为这比LinkedList开销要大很多。 LinkedList: 是线程不安全的,由列表实现的List。对顺序访问进行了优化,向List中间插入与删除得开销不大,随机访问则相对较慢(可用ArrayList代替)。它具有方法addFirst()、addLast()、getFirst()、getLast()、removeFirst()、removeLast(),这些方法(没有在任何接口或基类中定义过)使得LinkedList可以当作堆栈、队列和双向队列使用。 Vector类:是线程安全的,提供了实现可增长数组的功能,随着更多元素加入其中,数组变的更大。在删除一些元素之后,数组变小。ArrayList会比Vector快,他是非同步的,如果设计涉及到多线程,还是用Vector比较好一些。

什么是线程安全?

如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。 或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。

  线程安全问题都是由全局变量及静态变量引起的。   

若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。 线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。

线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据

1.2.2 Set 接口

Set(interface): 存入Set的每个元素必须是唯一的,这也是与List不同的,因为Set不保存重复元素。加入Set的Object必须定义equals()方法以确保对象的唯一性。Set与Collection有完全一样的接口。Set接口不保证维护元素的次序。 HashSet: HashSet能快速定位一个元素,存入HashSet的对象必须定义hashCode()。 TreeSet: 保持次序的Set,底层为树结构。使用它可以从Set中提取有序的序列。 LinkedHashSet: 具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。 HashSet采用散列函数对元素进行排序,这是专门为快速查询而设计的; LinkedHashSet内部使用散列以加快查询速度,同时使用链表维护元素的次序,使得看起来元素是以插入的顺序保存的。

2.0 Map

它有四个实现类,分别是HashMap Hashtable LinkedHashMap 和TreeMap. Map接口储存一组成对的键-值对象,提供key(键)到value(值)的映射,Map中的key不要求有序,不允许重复。value同样不要求有序,但可以重复。最常见的Map实现类HashMap,他的储存方式是哈希表,优点是查询指定元素效率高。 Map 接口的常用方法如下所示: ``` 方法摘要 void clear() 从此映射中移除所有映射关系(可选操作)。 boolean containsKey(Object key) 如果此映射包含指定键的映射关系,则返回 true。 boolean containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回 true。 Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射关系的 Set 视图。 boolean equals(Object o) 比较指定的对象与此映射是否相等。 V get(Object key) 返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。 int hashCode() 返回此映射的哈希码值。 boolean isEmpty() 如果此映射未包含键-值映射关系,则返回 true。 Set<K> keySet() 返回此映射中包含的键的 Set 视图。 V put(K key, V value) 将指定的值与此映射中的指定键关联(可选操作)。 void putAll(Map<? extends K,? extends V> m) 从指定映射中将所有映射关系复制到此映射中(可选操作)。 V remove(Object key) 如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。 int size() 返回此映射中的键-值映射关系数。 Collection<V> values() 返回此映射中包含的值的 Collection 视图。 ```

Map的一般用法 声明一个Map :

Map map = new HashMap();

向map中放值 ,注意: map是key-value的形式存放的,如:

map.put("sa","dd");

从map中取值 :

String str = map.get("sa").toString();

结果是: str = “dd’ 遍历一个map,从中取得key和value :

Map m= new HashMap(); for(Object obj : map.keySet()){ Object value = map.get(obj ); } package list; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; public class MapTest { public static void main(String[] args) { Map<String, Employee> staff = new HashMap<String, Employee>(); staff.put("144-25-5464", new Employee("Amy")); staff.put("567-24-2546", new Employee("Harry")); staff.put("157-62-7935", new Employee("Gray")); staff.put("456-62-5527", new Employee("France")); System.out.println(staff); staff.remove("567-24-2546");//删除 System.out.println(staff); staff.put("456-62-5527", new Employee("Bob"));//替换 System.out.println(staff); System.out.println(staff.get("157-62-7935"));//查询 //取得map中所有的key和value //Map.Entry()这个方法返回一个Map.Entry实例化后的对象集。接着,Map.Entry类提供了一个getKey()方法和一个getValue()方法 for(Map.Entry<String, Employee> entry : staff.entrySet()) { String key = entry.getKey(); Employee value = entry.getValue(); System.out.println("key=" + key + ", value=" + value + ""); } //取得map中所有的key Set<String> keys = staff.keySet(); for(String key : keys) { System.out.println(key); } //取得map中所有的value Collection<Employee> values = staff.values(); for(Employee value : values) { System.out.println(value); } } } class Employee { public Employee(String n) { name = n; salary = 0; } //toString() 方法可把一个逻辑值转换为字符串,并返回结果。返回该对象的字符串表示。通常,toString 方法会返回一个“以文本方式表示”此对象的字符串。结果应是一个简明但易于读懂的信息表达式。 public String toString() { return "[name=" + name + ", salary=" + salary + "]"; } private String name; private double salary; }

2.0.1 HashMap 和 Hashtable

在Map 中插入、删除和定位元素,HashMap 是最好的选择。

Hashtable和HashMap类有三个重要的不同之处。

第一个不同主要是历史原因。Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现。 也许最重要的不同是Hashtable的方法是同步的,而HashMap的方法不是。这就意味着,虽然你可以不用采取任何特殊的行为就可以在一个多线程的应用程序中用一个Hashtable,但你必须同样地为一个HashMap提供外同步。一个方便的方法就是利用Collections类的静态的synchronizedMap()方法,它创建一个线程安全的Map对象,并把它作为一个封装的对象来返回。这个对象的方法可以让你同步访问潜在的HashMap。这么做的结果就是当你不需要同步时,你不能切断Hashtable中的同步(比如在一个单线程的应用程序中),而且同步增加了很多处理费用。 第三点不同是,只有HashMap可以让你将空值作为一个表的条目的key或value。HashMap中只有一条记录可以是一个空的key,但任意数量的条目可以是空的value。这就是说,如果在表中没有发现搜索键,或者如果发现了搜索键,但它是一个空的值,那么get()将返回null。如果有必要,用containKey()方法来区别这两种情况。 一些资料建议,当需要同步时,用Hashtable,反之用HashMap。但是,因为在需要时,HashMap可以被同步,HashMap的功能比Hashtable的功能更多,而且它不是基于一个陈旧的类的,所以有人认为,在各种情况下,HashMap都优先于Hashtable。 import java.util.Map; import java.util.HashMap; import java.util.Set; import java.util.HashSet; import java.util.Iterator; import java.util.Hashtable; import java.util.TreeMap; class HashMaps { public static void main(String[] args) { Map map=new HashMap(); map.put("a", "aaa"); map.put("b", "bbb"); map.put("c", "ccc"); map.put("d", "ddd"); Iterator iterator = map.keySet().iterator(); while (iterator.hasNext()) { Object key = iterator.next(); System.out.println("map.get(key) is :"+map.get(key)); } //Hashtable 排序是无序的 Hashtable tab=new Hashtable(); tab.put("a", "aaa"); tab.put("b", "bbb"); tab.put("c", "ccc"); tab.put("d", "ddd"); Iterator iterator_1 = tab.keySet().iterator(); while (iterator_1.hasNext()) { Object key = iterator_1.next(); System.out.println("tab.get(key) is :"+tab.get(key)); } TreeMap tmp=new TreeMap(); tmp.put("a", "aaa"); tmp.put("b", "bbb"); tmp.put("c", "ccc"); tmp.put("d", "ddd"); Iterator iterator_2 = tmp.keySet().iterator(); while (iterator_2.hasNext()) { Object key = iterator_2.next(); System.out.println("tmp.get(key) is :"+tmp.get(key)); } } } //执行完后,果然是这样的(hashmap和hashtable是没有顺序的,而treemap则是按顺序排列的哦!!) //HashMap和Hashtable都实现了Map接口主要的区别有:线程安全性,同步(synchronization),以及速度。

TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。

LinkedHashMap 是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现. (应用场景:购物车等需要顺序的)

2.0.1 和 Hashtable LinkedHashMap 和TreeMap.

TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。 LinkedHashMap 是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现. (应用场景:购物车等需要顺序的) public void useTreeMap() throws Exception { response.getWriter().println("------有序(但是按默认顺充,不能指定)------"); Map<String, String> map = new TreeMap<String, String>(); map.put("1", "Level 1"); map.put("2", "Level 2"); map.put("3", "Level 3"); map.put("a", "Level a"); map.put("b", "Level b"); map.put("c", "Level c"); Iterator<Entry<String, String>> it = map.entrySet().iterator(); while (it.hasNext()) { Entry<String, String> e = it.next(); response.getWriter().println("Key: " + e.getKey() + "; Value: " + e.getValue()); } } public void useLikedHashMap() throws Exception { response.getWriter().println("------有序(根据输入的顺序输出)------"); Map<String, String> map = new LinkedHashMap<String, String>(); map.put("1", "Level 1"); map.put("2", "Level 2"); map.put("3", "Level 3"); map.put("a", "Level a"); map.put("b", "Level b"); map.put("c", "Level c"); Iterator<Entry<String, String>> it = map.entrySet().iterator(); while (it.hasNext()) { Entry<String, String> e = it.next(); response.getWriter().println("Key: " + e.getKey() + "; Value: " + e.getValue()); } } ------有序(但是按默认顺充,不能指定)------ Key: 1; Value: Level 1 Key: 2; Value: Level 2 Key: 3; Value: Level 3 Key: a; Value: Level a Key: b; Value: Level b Key: c; Value: Level c ------有序(根据输入的顺序输出)------ Key: 1; Value: Level 1 Key: 2; Value: Level 2 Key: 3; Value: Level 3 Key: a; Value: Level a Key: b; Value: Level b Key: c; Value: Level c
转载请注明原文地址: https://www.6miu.com/read-10173.html

最新回复(0)