【Java容器】Java容器框架解析


(点线框:接口,实线框:实现(具体)类,空心箭头:特定的类实现了一个接口,实心箭头:某个类可以生成箭头所指向类的对象)

Java容器类库划分为2个不同概念:

1)Collection。保存单一的元素。List按照插入的顺序保存元素,而Set不能有重复元素。Queue按照排队规则来确定对象产生的顺序。

2)Map。保存一组成对的“键值对”对象。


List接口

用以实现数组、队列、栈等。像数组一样,List也建立数字索引与对象的关联,因此,数组和List都是排好序的容器。List能够自动扩充容量。

有2种类型的List:

  • ArrayList,随机访问元素性能优异,但是在List中间插入和移除元素时较慢。
  • LinkedList,插入和删除更高效,但是随机访问效能稍差,LinkedList还添加了可以使其用作栈、队列或双端队列的方法。如getFirst()、element()、removeFirst()、remove()、removeLast()、addFirst、add()、addLast()[以上方法在元素不存在时抛NoSuchElementException]、peek()、poll()、offer()[以上方法为空时返回null]。并且LinkedList实现了Queue接口。LinkedList也是实现了Deque接口,这样具备了双向队列的功能。

Set接口

不保存重复的元素(通过equals和hashcode保证),和Collection完全一样的接口,因此没有实现任何额外的功能。加入Set的元素必须定义equals方法以确保对象的唯一性。无序。

HashSet:为加快查找而设计的Set。存入HashSet的元素必须定义hasCode()

TreeSet:保持次序的Set,底层为树结构。可以从Set中提取有序的序列。元素必须实现Compareble接口。

LinkedHashSet:具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入顺序)。在迭代遍历Set时,会按元素插                入的次序显示元素也必须实现HashCode()方法。

SortedSet:保证元素处于排序状态。


在覆盖equals时,总是覆盖hasCode(),因为equals相同,则hashCode()必定相同,而hasCode()相等,则equals不一定相等。因此在往Set中插入的时候,如果equals()相同,而如果hashCode不相同,就会往不同的位置插入2个相同对象,造成空间浪费,而如果hashCode()相同,equals()不同,那么就会往相同的位置插入元素,因为两个元素不等,所以可以插入,而事实却不能插入。


Map接口 :

HashMap,TreeMap,LinkedHashMap,WeakHashMap,CourrentHashMap,IdentityHashMap,都实现基本的Map接口。

HashMap:Map基于散列表的实现(取代了Hashtable)。插入和查询键值对的开销是固定的。可以通过构造器设置容量和负载因子,以调整容器的性能。
LinkedHashMap:类似于HashMap,但迭代时,取得键值对的顺序是其插入顺序,或者是最近最少使用LRU的次序。只比                             HashMap慢 一点;而在迭代时速度反而更快,因为它使用链表维护内部次序。
TreeMap:基于红黑树的实现。查看”键“或”键值对“时,他们会排序(次序由Comparable或Comparator决定)。
         特点在于,所得到的结果是经过排序的。TreeMap是唯一带有subMap()方法的Map,它返回一个子树。
WeakHashMap:弱碱映射,允许释放映射索指向的对象;每个值值保存一份实例以节省存储空间。允许垃圾回收器自动清理键和值。
ConcurrentMap:一种线程安全的Map,不涉及同步加锁。
IndentiyMap:使用==代替equals对健进行比较的散列映射。
总结:Hashtable性能与HashMap大题相当。TreeMap通常比HashMap要慢。LinkedHashMap在插入时比HashMap慢一点,但迭代时更快。

Queue接口

在JDK 5仅有的两个实现是LinkedList和PrioprityQueue.
LinkedList提供了方法以支持队列的行为,并且它实现了Queue接口,因此LinkedList可以用作Queue的一种实现。

Java 1.0/1.1容器:

Vector:基本可看作ArrayList

Enumeration接口:Java1.0/1.1的迭代器。接口比Iterator小。

Hashtable:与HashMap相似。

Stack:不是用Vertor来构建,而是继承。不要使用它。


Collection 和Iterator

Collection是描述所有序列容器的共性的跟接口。java.util.AbstractCollection类提供了Collection的默认实现,使得你可以创建AbstractCollection的子类型。

Java SE引入Iterable<T>接口,该接口只包含一个能够产生Iterator<E>类型的iterator()方法,并且Iterable接口被foreach用来在序列中移动。iterator方法返回的是实现了Iterator<>的匿名内部类的实例。因此如果创建任何实现Iterable的类,都可以将它用于foreach语句中。Collection接口继承Iterable接口,这样使得不同的实现了Collection接口的容器自己去实现Iterable中的iterator()方法并返回根据自己结构特点进行遍历的Iterator内部实例,这样实现了迭代器Iterator与不同容器底层实现的解耦合(这就是所谓的代器模式)。如果在容器(也包括我们自己实现的容器)内部需要实现多个迭代方式,直接继承Iterable类并覆盖iterator方法,只能替换现有的方法,不能同时实现多个迭代方式,这时候我们可以实现Collection接口或者继承AbstractionCollection或者继承ArrayList等具体容器实现类,使用适配器模式即有了一个接口我们可以用一个方法提供不同的接口返回实例,然后在方法的实现中提供不同的接口实例的实现方式,例如我们需要一个220V的电源,而现在只有一个110V的电源,那么我们可以继承电源接口,然后自己添加一个转换方法返回一个电源的实例,而实例的内部实现,就是110V转220V的实现过程。即所谓的适配器模式。附上一个通过适配Iterable接口 实现不同foreach迭代方式的完整代码:



package collection;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;

 class ReversibleArrayList<T> extends ArrayList<T> {
	 /**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public ReversibleArrayList(Collection<T> c) {super(c);}
	
	public Iterable<T> reversed() {
		return new Iterable<T>() {
				public Iterator<T> iterator() {
					return new Iterator<T>() {
						int current = size()-1;
						@Override
						public boolean hasNext() {
							// TODO Auto-generated method stub
							return current>-1;
						}

						@Override
						public T next() {
							// TODO Auto-generated method stub
							return get(current--);
						}

						@Override
						public void remove() {
							// TODO Auto-generated method stub
							
						}
						
						
					};
				
				}
		};
			
	};			
		
}

 public class AdapterMethodIterable {
	 public static void main(String[] args) {
		 
		 ReversibleArrayList<String> ral = new ReversibleArrayList<String>(Arrays.asList("To be or not to be".split(" ")));
		 for(String s: ral) {
			 
			 System.out.print(s+" ");
		 }
		 System.out.println();
		 for(String s:ral.reversed()) {
			 System.out.print(s+" ");
		 }
	 }
	 
 }
 

扯的有点远了,但是通过这个例子和以上讲解不难看出,为什么会把Iterator接口封装在Iterable接口内部的原因,一个是为了所谓的封闭原则,还有个就是为了更灵活的进行多态的适配,使一个容器实现出不同的迭代方式,即通过不同的迭代方法返回不同的迭代对象。这也为后续实现Collection接口的容器类提供了迭代方式的可扩展性。即Iterable相当于适配接口,而Iterator相当于电源。


总结:

Collection是List、Set等集合高度抽象出来的接口,它包含了这些集合的基本操作,它主要又分为两大部分:List和Set。

    List接口通常表示一个列表(数组、队列、链表、栈等),其中的元素可以重复,常用实现类为ArrayList和LinkedList,另外还有不常用的Vector。另外,LinkedList还是实现了Queue接口,因此也可以作为队列使用。

    Set接口通常表示一个集合,其中的元素不允许重复(通过hashcode和equals函数保证),常用实现类有HashSet和TreeSet,HashSet是通过Map中的HashMap实现的,而TreeSet是通过Map中的TreeMap实现的。另外,TreeSet还实现了SortedSet接口,因此是有序的集合(集合中的元素要实现Comparable接口,并覆写Compartor函数才行)。

    我们看到,抽象类AbstractCollection、AbstractList和AbstractSet分别实现了Collection、List和Set接口,这就是在Java集合框架中用的很多的适配器设计模式,用这些抽象类去实现接口,在抽象类中实现接口中的若干或全部方法,这样下面的一些类只需直接继承该抽象类,并实现自己需要的方法即可,而不用实现接口中的全部抽象方法。

    Map是一个映射接口,其中的每个元素都是一个key-value键值对,同样抽象类AbstractMap通过适配器模式实现了Map接口中的大部分函数,TreeMap、HashMap、WeakHashMap等实现类都通过继承AbstractMap来实现,另外,不常用的HashTable直接实现了Map接口,它和Vector都是JDK1.0就引入的集合类。

    Iterator是遍历集合的迭代器(不能遍历Map,只用来遍历Collection),Collection的实现类都实现了iterator()函数,它返回一个Iterator对象,用来遍历集合,ListIterator则专门用来遍历List。而Enumeration则是JDK1.0时引入的,作用与Iterator相同,但它的功能比Iterator要少,它只能再Hashtable、Vector和Stack中使用。

    Arrays和Collections是用来操作数组、集合的两个工具类,例如在ArrayList和Vector中大量调用了Arrays.Copyof()方法,而Collections中有很多静态方法可以返回各集合类的synchronized版本,即线程安全的版本,当然了,如果要用线程安全的结合类,首选Concurrent并发包下的对应的集合类。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值