zoukankan      html  css  js  c++  java
  • Java之集合(一)接口及抽象类

      转载请注明源出处:http://www.cnblogs.com/lighten/p/7278655.html

    1.前言

      从本章开始介绍Java的集合类,这些类主要存在于java.util包下,该系列基于JDK8,类中所包含的JDK8的lambda表达式的相关内容不进行介绍,只关注集合本身的使用方法。

    2.集合体系

      

      上图就是Java中的集合主要层次结构了,所有的集合都需要实现Iterable<T>接口,最上层的是通用的Collection接口定义,然后就是较为熟悉的三种结构:List、Queue和Set了。下面又根据不同的特性有了子类接口。右图就是相关的抽象实现了,所有具体的类都会对应继承这些抽象实现。Map不在本章讨论范围内,之后涉及到的时候会先讲解Map的实现。

    3.接口定义和部分实现

    3.1 Collection

      上图是JDK8中集合的接口定义,不关注JDK8的新特性,有如下接口:

      1.size():集合中元素的个数

      2.isEmpty():集合是否为空

      3.contain(Object):集合是否包含某个元素

      4.iterator():获取集合的迭代器

      5.toArray():返回集合中的元素数组

      6.toArray(T[]):将集合中的元素放入所给数组中,如果所给数组大于集合大小,补充null。如果数组小于集合大小,返回数组大小的集合元素(实际集合元素个数小于数组大小依旧补充null)。

      7.add(E):向集合中添加一个元素

      8.remove(Object):在集合中移除指定的元素

      9.containsAll(Collection<?>):集合是否包含指定集合的全部元素,有一个没有就返回false

      10.addAll(Collection<?>):将指定的集合中全部的元素添加到该集合中,返回值的含义并不是全部成功,而是集合的元素有所改变就是true.(做并集A∪B)

      11.removeAll(Collection<?>):将指定的集合中全部的元素都从该集合中移除,返回值的含义是移除操作造成该集合有所改变就是true。(A-A∩B)

      12.retainAll(Collection<?>):这个方法和removeAll相反,其含义是该集合只保留指定集合中的元素,移除其它元素,有改变就是true。(实际就是做交集,保留交集部分A∩B)

      上述方法就是每一个集合所必备的相关方法。AbstractCollection抽象类中,几乎实现了所有的接口方法,除了以下三个:size()、iterator()和add()方法,其它方法的实现都是基于这三个抽象方法的(add不是抽象方法,其直接抛出异常,需要子类覆盖,所以此处也视为抽象方法)。当然,实现的方法也许在子类中会被覆盖,不过也基本是实现完了可以实现的功能。

    3.2 List

      List接口继承自Collection接口。除了Collection接口的方法外,还增加了以下与位置相关的方法:

      1.get(int):获取指定位置的元素

      2.set(int,E):替换指定位置的元素

      3.add(int,E):将元素插入指定位置

      4.remove(int):移除指定位置的元素

      5.indexOf(Object):返回指定元素第一次在list中出现的位置,没有就是-1

      6.lastIndexOf(Object):返回指定元素最后一次在list中出现的位置,没有就是-1

      7.listIterator():返回一个list类型的迭代器,比一般的迭代器提供了前移的方法

      8.listIterator(int):返回一个从指定位置开始的list的list类型迭代器。

      9.subList(int,int):返回一个子list,范围是[start,end)

      10.addAll(int, Collection):将一个集合中的元素从指定位置开始全部插入

      list接口的抽象类AbstractList也是对应的继承了AbstractCollection类,当然也需要实现list接口。对于AbstractCollection中实现的方法,AbstractList大体没有变化,除了add(E)和iterator()方法其有具体实现了。add(E)方法是通过add(int,E)方法实现的,其它与位置有关list接口定义的方法都没有实现,需要具体子类去覆盖实现。其它值得一提的方法有indexOf和lastIndexOf,clear()等方法,其实现都是通过listIterator()迭代器完成的,而不是一般的迭代器。而后重要的就是三个实现类了:Itr、ListItr和SubList。

      Itr这个普通的迭代器的内容很简单,就如上图。cursor是当前读取的元素下标,所以hasNext的判断就是其不等于list大小就是true。lastRet是记录上一个位置,原因是调用next的时候cursor会自增1,这个时候remove方法就得需要上一次的位置才能删除当前对象。expectedModCount是用来判断并发修改的,迭代器虽然允许边遍历边删除,但是并不允许并发遍历删除。了解了这个,其实现也就很好理解:

      ListItr的实现是继承了Itr类的,其就是增加了前移操作和set、add操作,操作也依旧容易,根据Itr的原理,只需要处理cursor和lastRet就可以了。

      set和add方法就是通过当前位置来调用list的相关方法完成。

      SubList是直接继承自AbstractList类的,其接受一个list,和起始,终止坐标。但是要注意的是,SubList持有的是传入的list的引用,对SubList进行修改操作都会影响原list的内容,其只是限定了一下操作边界而已,并不是真正意义上的一个新的拷贝list。并且多线程操作sublist是不允许的,按照代码来看,多线程操作不同的sublist,这些sublist持有同一个list也是不被允许的。

        @Test
    	public void test() {
    		List<Integer> list = new ArrayList<>();
    		for(int i = 0; i < 5; i++) {
    			list.add(i);
    		}
    		List<Integer> sub = list.subList(1, 3);
    		sub.set(0, 100);
    		System.out.println(Arrays.toString(list.toArray()));
    	}

    测试多线程的情况:

        @Test
    	public void test2() throws InterruptedException {
    		int threadNum = 3;
    		int all = 10000;
    		List<Integer> list = new ArrayList<>();
    		for(int i = 0; i < all; i++) {
    			list.add(i);
    		}
    		int per = all / threadNum;
    		CountDownLatch latch = new CountDownLatch(threadNum);
    		ExecutorService service = Executors.newCachedThreadPool();
    		CyclicBarrier barrier = new CyclicBarrier(threadNum);
    		for(int i = 0; i < threadNum; i++) {
    			service.submit(new TestTask(list.subList(i*per, (i+1)*per), barrier, latch));
    		}
    		latch.await();
    	}
    
    
    class TestTask implements Runnable {
    	
    	private List<Integer> sub;
    	private CyclicBarrier barrier;
    	private CountDownLatch latch;
    	
    	public TestTask(List<Integer> sub, CyclicBarrier barrier, CountDownLatch latch) {
    		this.sub = sub;
    		this.barrier = barrier;
    		this.latch = latch;
    	}
    	
    	public TestTask(List<Integer> sub, CountDownLatch latch) {
    		this.sub = sub;
    		this.latch = latch;
    	}
    
    	@Override
    	public void run() {
    		try {
    			if(barrier != null) {
    				barrier.await();
    			}
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		} catch (BrokenBarrierException e) {
    			e.printStackTrace();
    		}
    		try {
    			System.out.println(Thread.currentThread().getName());
    			for(int i = 0; i < sub.size(); i++) {
    				sub.remove(i);
    			}
    			System.out.println(Thread.currentThread().getName()+" over!");
    		} catch(Throwable e) {
    			e.printStackTrace();
    		} finally {
    			latch.countDown();
    		}
    	}
    	
    }

      这个测试实际上并不规范,第一个实际运行的时候没有模拟出并发,看允许还是一个个线程执行的,第二个是sublist并不是抽象父类中的sublist,ArrayList重写了这个sublist。但还是可以参考一下。

    3.3 Queue

      Queue队列结构也是继承了Collection接口,上图是其独自定义的一些方法。

      1.add(E):添加一个元素入队列,队列有容量限制时,超过容量抛出异常

      2.offer(E):添加一个元素入队列,在队列有容量限制的时候比add方法更好,不会抛出异常

      3.remove():检索并移除队列头,与poll不一样的地方在于如果队列为空,抛出异常

      4.poll():检索并移除队列头,队列为空返回NULL

      5.element():检索不移除,返回队列头,队列为空抛出异常

      6.peek():检索不移除,返回队列头,队列为空返回NULL

      AbstractQueue继承了AbstractCollection类,并实现Queue接口。其实现了add、remove和element方法,做法是借助未实现的offer、poll和peek方法,没有什么可说的地方。

     3.4 Set

      Set接口继承了Collection,并没有添加新的方法。其抽象实现类AbstractSet也没有做什么改变,AbstractCollection未实现的add,size,iterator均没有实现,只是重写了一下removeAll方法,减少了一下迭代次数而已。

  • 相关阅读:
    使用ALAssetsLibrary读取所有照片
    dispatch_after中时间的计算
    UICollectionView的header悬停
    ios侧滑返回:完美解决 interactivePopGestureRecognizer 卡住的问题
    自定义TabBar
    automaticallyAdjustsScrollViewInsets(UITextView文字顶部留有空白)
    kvo&kvc
    调用iPhone的短信
    Windows 10中Oracle数据库导出到Access数据库(MDB)
    HP Z620 Windows 7 系统安装(含磁盘阵列)
  • 原文地址:https://www.cnblogs.com/lighten/p/7278655.html
Copyright © 2011-2022 走看看