博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java集合框架中的三层体系
阅读量:4136 次
发布时间:2019-05-25

本文共 20839 字,大约阅读时间需要 69 分钟。

一.抽象类

  在了解抽象类之前,先来了解一下抽象方法。抽象方法是一种特殊的方法:它只有声明,而没有具体的实现。抽象方法的声明格式为:

abstract void fun();

抽象方法必须用abstract关键字进行修饰。如果一个类含有抽象方法,则称这个类为抽象类,抽象类必须在类前用abstract关键字修饰。因为抽象类中含有无具体实现的方法,所以不能用抽象类创建对象。

  下面要注意一个问题:在《JAVA编程思想》一书中,将抽象类定义为“包含抽象方法的类”,但是后面发现如果一个类不包含抽象方法,只是用abstract修饰的话也是抽象类。也就是说抽象类不一定必须含有抽象方法。个人觉得这个属于钻牛角尖的问题吧,因为如果一个抽象类不包含任何抽象方法,为何还要设计为抽象类?所以暂且记住这个概念吧,不必去深究为什么。

abstract class ClassName {    abstract void fun();}

从这里可以看出,抽象类就是为了继承而存在的,如果你定义了一个抽象类,却不去继承它,那么等于白白创建了这个抽象类,因为你不能用它来做任何事情。对于一个父类,如果它的某个方法在父类中实现出来没有任何意义,必须根据子类的实际需求来进行不同的实现,那么就可以将这个方法声明为abstract方法,此时这个类也就成为abstract类了。

  包含抽象方法的类称为抽象类,但并不意味着抽象类中只能有抽象方法,它和普通类一样,同样可以拥有成员变量和普通的成员方法。注意,抽象类和普通类的主要有三点区别:

  1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。

  2)抽象类不能用来创建对象;

  3)如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。

  在其他方面,抽象类和普通的类并没有区别。

二.接口

  接口,英文称作interface,在软件工程中,接口泛指供别人调用的方法或者函数。从这里,我们可以体会到Java语言设计者的初衷,它是对行为的抽象。在Java中,定一个接口的形式如下:

interface InterfaceName {}

接口中可以含有 变量和方法。但是要注意,接口中的变量会被隐式地指定为public static final变量(并且只能是public static final变量,用private修饰会报编译错误),而方法会被隐式地指定为public abstract方法且只能是public abstract方法(用其他关键字,比如private、protected、static、 final等修饰会报编译错误),并且接口中所有的方法不能有具体的实现,也就是说,接口中的方法必须都是抽象方法。从这里可以隐约看出接口和抽象类的区别,接口是一种极度抽象的类型,它比抽象类更加“抽象”,并且一般情况下不在接口中定义变量。

  要让一个类遵循某组特地的接口需要使用implements关键字,具体格式如下:

class ClassName implements Interface1,Interface2,[....]{}

可以看出,允许一个类遵循多个特定的接口。如果一个非抽象类遵循了某个接口,就必须实现该接口中的所有方法。对于遵循某个接口的抽象类,可以不实现该接口中的抽象方法。

三.抽象类和接口的区别

1.语法层面上的区别

  1)抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;

  2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;

  3)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;

  4)一个类只能继承一个抽象类,而一个类却可以实现多个接口。

2.设计层面上的区别

  1)抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。举个简单的例子,飞机和鸟是不同类的事物,但是它们都有一个共性,就是都会飞。那么在设计的时候,可以将飞机设计为一个类Airplane,将鸟设计为一个类Bird,但是不能将 飞行 这个特性也设计为类,因此它只是一个行为特性,并不是对一类事物的抽象描述。此时可以将 飞行 设计为一个接口Fly,包含方法fly( ),然后Airplane和Bird分别根据自己的需要实现Fly这个接口。然后至于有不同种类的飞机,比如战斗机、民用飞机等直接继承Airplane即可,对于鸟也是类似的,不同种类的鸟直接继承Bird类即可。从这里可以看出,继承是一个 "is-a(是不是)"的关系,而 接口 实现则是 "like-a(有没有)"的关系。如果一个类继承了某个抽象类,则子类必定是抽象类的种类,而接口实现则是有没有、具备不具备的关系,比如鸟是否能飞(或者是否具备飞行这个特点),能飞行则可以实现这个接口,不能飞行就不实现这个接口。

  2)设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。什么是模板式设计?最简单例子,大家都用过ppt里面的模板,如果用模板A设计了ppt B和ppt C,ppt B和ppt C公共的部分就是模板A了,如果它们的公共部分需要改动,则只需要改动模板A就可以了,不需要重新对ppt B和ppt C进行改动。而辐射式设计,比如某个电梯都装了某种报警器,一旦要更新报警器,就必须全部更新。也就是说对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。

我们来看下接口和抽象类在集合框架的类图继承体系中的使用: 

四.程序设计的三个层次

根据上图我们来分析下集合类继承体系的设计:

· 整体的代码结构都像一棵树,有一个唯一的根节点,这个根节点封装了这个类族的公有特性

· 有一层抽象类或者类似抽象类作用的类,它们实现了通用的方法。方便用户扩展自己的业务。

· 有具体的实现,用户可以直接使用这些具体实现。

这些相似的地方其实可以归纳为三个结构层次:

1. 一个高度抽象的根节点接口,可以再抽象出一组带有具体操作的接口来实现我们的根节点

2. 一组抽象类,实现带有具体操作接口的部分方法,方便用户快速扩展自己的业务。

3. 具体的实现,方便用户直接调用。

这个套路在Java一些开源框架中是很常见的,这样做的好处也显而易见,比较易于维护和扩展。

 

4.1.三个层次在集合体系中的运用

结合着Java集合类的继承图一起来看下是如何分为三个层次的,首先由于Map和Collection的相似点很少,所以这两部分的根节点是分开的。

我们拿Collection这部分来说,首先定义了一组接口。Collection是List、Set等集合高度抽象出来的接口,它包含了这些集合的基本操作,它主要又分为:List、Set和Queue,分别对应线性表、集合、队列,实现对应的接口,则有了对应数据结构的特性。这是第一个结构层次,

然后又定义了一组抽象类,我们拿AbstractCollection类来说,先看下注释

/** * This class provides a skeletal implementation of the Collection * interface, to minimize the effort required to implement this interface. 

*/

这个类实现了Collection接口的骨架,用户继承这个类可以用最小化的时间来实现一个集合。

其他的抽象类也都是各个数据结构的骨架,用户可以自定义自己的集合。

最后第三个层次就是具体的实现类了,比如我们常用的ArrayList、LinkedList等等。比如LinkedList实现了List和Queue接口,那么它既有队列先进先出的特性,又有List可以通过位置访问元素的特性。

 

源码的具体实现(jdk的源码路径C:\Program Files\Java\src\java\util)

Collection部分

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

Collection接口

/** * The root interface in the collection hierarchy.  A collection * represents a group of objects, known as its elements.  Some * collections allow duplicate elements and others do not.  Some are ordered * and others unordered.  The JDK does not provide any direct * implementations of this interface: it provides implementations of more * specific subinterfaces like Set and List.  This interface * is typically used to pass collections around and manipulate them where * maximum generality is desired. */

集合层次结构的根。一个集合包含一组元素对象。有一些集合允许重复元素,有一些不允许;有一些集合元素是有序的有一些不是。

定义的方法:

int size()

boolean isEmpty()

boolean contains(Object o)

Iterator iterator()

Object[] toArray()

T[] toArray(T[] a)

boolean add(E e)

boolean remove(Object o)

boolean containsAll(Collection c)

boolean addAll(Collection c)

boolean removeAll(Collection c)

boolean retainAll(Collection c)

void clear()

 

AbstractCollection抽象类

/** * This class provides a skeletal implementation of the Collection * interface, to minimize the effort required to implement this interface. 

* * To implement an unmodifiable collection, the programmer needs only to * extend this class and provide implementations for the iterator and * size methods. (The iterator returned by the iterator * method must implement hasNext and next.)

* * To implement a modifiable collection, the programmer must additionally * override this class's add method (which otherwise throws an * UnsupportedOperationException), and the iterator returned by the * iterator method must additionally implement its remove * method.

* * The programmer should generally provide a void (no argument) and * Collection constructor, as per the recommendation in the * Collection interface specification.

* * The documentation for each non-abstract method in this class describes its * implementation in detail. Each of these methods may be overridden if * the collection being implemented admits a more efficient implementation.

*/

这个类实现了Collection接口的骨架,用户继承这个类可以用最小化的时间来实现一个集合。

查看这个抽象类的源码会发现(见本文档的最后面),这个抽象类的大多数成员函数都有默认的实现,如果我们需要实现一个简单的集合,只需要重写iterator()、int size()和add(E o)方法,同时这个集合的特性取决于我们的实现方式。

1.本文参考:

2.Jdk中AbstractCollection抽象类的实现:

package java.util;/** * This class provides a skeletal implementation of the Collection * interface, to minimize the effort required to implement this interface. 

* * To implement an unmodifiable collection, the programmer needs only to * extend this class and provide implementations for the iterator and * size methods. (The iterator returned by the iterator * method must implement hasNext and next.)

* * To implement a modifiable collection, the programmer must additionally * override this class's add method (which otherwise throws an * UnsupportedOperationException), and the iterator returned by the * iterator method must additionally implement its remove * method.

* * The programmer should generally provide a void (no argument) and * Collection constructor, as per the recommendation in the * Collection interface specification.

* * The documentation for each non-abstract method in this class describes its * implementation in detail. Each of these methods may be overridden if * the collection being implemented admits a more efficient implementation.

* * This class is a member of the * * Java Collections Framework. * * @author Josh Bloch * @author Neal Gafter * @see Collection * @since 1.2 */public abstract class AbstractCollection

implements Collection
{ /** * Sole constructor. (For invocation by subclass constructors, typically * implicit.) */ protected AbstractCollection() { } // Query Operations /** * Returns an iterator over the elements contained in this collection. * * @return an iterator over the elements contained in this collection */ public abstract Iterator
iterator(); public abstract int size(); /** * {@inheritDoc} * *

This implementation returns size() == 0. */ public boolean isEmpty() { return size() == 0; } /** * {@inheritDoc} * *

This implementation iterates over the elements in the collection, * checking each element in turn for equality with the specified element. * * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public boolean contains(Object o) { Iterator

it = iterator(); if (o==null) { while (it.hasNext()) if (it.next()==null) return true; } else { while (it.hasNext()) if (o.equals(it.next())) return true; } return false; } /** * {@inheritDoc} * *

This implementation returns an array containing all the elements * returned by this collection's iterator, in the same order, stored in * consecutive elements of the array, starting with index {@code 0}. * The length of the returned array is equal to the number of elements * returned by the iterator, even if the size of this collection changes * during iteration, as might happen if the collection permits * concurrent modification during iteration. The {@code size} method is * called only as an optimization hint; the correct result is returned * even if the iterator returns a different number of elements. * *

This method is equivalent to: * *

 {@code     * List
list = new ArrayList
(size()); * for (E e : this) * list.add(e); * return list.toArray(); * }
*/ public Object[] toArray() { // Estimate size of array; be prepared to see more or fewer elements Object[] r = new Object[size()]; Iterator
it = iterator(); for (int i = 0; i < r.length; i++) { if (! it.hasNext()) // fewer elements than expected return Arrays.copyOf(r, i); r[i] = it.next(); } return it.hasNext() ? finishToArray(r, it) : r; } /** * {@inheritDoc} * *

This implementation returns an array containing all the elements * returned by this collection's iterator in the same order, stored in * consecutive elements of the array, starting with index {@code 0}. * If the number of elements returned by the iterator is too large to * fit into the specified array, then the elements are returned in a * newly allocated array with length equal to the number of elements * returned by the iterator, even if the size of this collection * changes during iteration, as might happen if the collection permits * concurrent modification during iteration. The {@code size} method is * called only as an optimization hint; the correct result is returned * even if the iterator returns a different number of elements. * *

This method is equivalent to: * *

 {@code     * List
list = new ArrayList
(size()); * for (E e : this) * list.add(e); * return list.toArray(a); * }
* * @throws ArrayStoreException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public
T[] toArray(T[] a) { // Estimate size of array; be prepared to see more or fewer elements int size = size(); T[] r = a.length >= size ? a : (T[])java.lang.reflect.Array .newInstance(a.getClass().getComponentType(), size); Iterator
it = iterator(); for (int i = 0; i < r.length; i++) { if (! it.hasNext()) { // fewer elements than expected if (a == r) { r[i] = null; // null-terminate } else if (a.length < i) { return Arrays.copyOf(r, i); } else { System.arraycopy(r, 0, a, 0, i); if (a.length > i) { a[i] = null; } } return a; } r[i] = (T)it.next(); } // more elements than expected return it.hasNext() ? finishToArray(r, it) : r; } /** * The maximum size of array to allocate. * Some VMs reserve some header words in an array. * Attempts to allocate larger arrays may result in * OutOfMemoryError: Requested array size exceeds VM limit */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * Reallocates the array being used within toArray when the iterator * returned more elements than expected, and finishes filling it from * the iterator. * * @param r the array, replete with previously stored elements * @param it the in-progress iterator over this collection * @return array containing the elements in the given array, plus any * further elements returned by the iterator, trimmed to size */ private static
T[] finishToArray(T[] r, Iterator
it) { int i = r.length; while (it.hasNext()) { int cap = r.length; if (i == cap) { int newCap = cap + (cap >> 1) + 1; // overflow-conscious code if (newCap - MAX_ARRAY_SIZE > 0) newCap = hugeCapacity(cap + 1); r = Arrays.copyOf(r, newCap); } r[i++] = (T)it.next(); } // trim if overallocated return (i == r.length) ? r : Arrays.copyOf(r, i); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError ("Required array size too large"); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } // Modification Operations /** * {@inheritDoc} * *

This implementation always throws an * UnsupportedOperationException. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} * @throws IllegalStateException {@inheritDoc} */ public boolean add(E e) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} * *

This implementation iterates over the collection looking for the * specified element. If it finds the element, it removes the element * from the collection using the iterator's remove method. * *

Note that this implementation throws an * UnsupportedOperationException if the iterator returned by this * collection's iterator method does not implement the remove * method and this collection contains the specified object. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public boolean remove(Object o) { Iterator

it = iterator(); if (o==null) { while (it.hasNext()) { if (it.next()==null) { it.remove(); return true; } } } else { while (it.hasNext()) { if (o.equals(it.next())) { it.remove(); return true; } } } return false; } // Bulk Operations /** * {@inheritDoc} * *

This implementation iterates over the specified collection, * checking each element returned by the iterator in turn to see * if it's contained in this collection. If all elements are so * contained true is returned, otherwise false. * * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @see #contains(Object) */ public boolean containsAll(Collection

c) { for (Object e : c) if (!contains(e)) return false; return true; } /** * {@inheritDoc} * *

This implementation iterates over the specified collection, and adds * each object returned by the iterator to this collection, in turn. * *

Note that this implementation will throw an * UnsupportedOperationException unless add is * overridden (assuming the specified collection is non-empty). * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} * @throws IllegalStateException {@inheritDoc} * * @see #add(Object) */ public boolean addAll(Collection

c) { boolean modified = false; for (E e : c) if (add(e)) modified = true; return modified; } /** * {@inheritDoc} * *

This implementation iterates over this collection, checking each * element returned by the iterator in turn to see if it's contained * in the specified collection. If it's so contained, it's removed from * this collection with the iterator's remove method. * *

Note that this implementation will throw an * UnsupportedOperationException if the iterator returned by the * iterator method does not implement the remove method * and this collection contains one or more elements in common with the * specified collection. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * * @see #remove(Object) * @see #contains(Object) */ public boolean removeAll(Collection

c) { boolean modified = false; Iterator
it = iterator(); while (it.hasNext()) { if (c.contains(it.next())) { it.remove(); modified = true; } } return modified; } /** * {@inheritDoc} * *

This implementation iterates over this collection, checking each * element returned by the iterator in turn to see if it's contained * in the specified collection. If it's not so contained, it's removed * from this collection with the iterator's remove method. * *

Note that this implementation will throw an * UnsupportedOperationException if the iterator returned by the * iterator method does not implement the remove method * and this collection contains one or more elements not present in the * specified collection. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * * @see #remove(Object) * @see #contains(Object) */ public boolean retainAll(Collection

c) { boolean modified = false; Iterator
it = iterator(); while (it.hasNext()) { if (!c.contains(it.next())) { it.remove(); modified = true; } } return modified; } /** * {@inheritDoc} * *

This implementation iterates over this collection, removing each * element using the Iterator.remove operation. Most * implementations will probably choose to override this method for * efficiency. * *

Note that this implementation will throw an * UnsupportedOperationException if the iterator returned by this * collection's iterator method does not implement the * remove method and this collection is non-empty. * * @throws UnsupportedOperationException {@inheritDoc} */ public void clear() { Iterator

it = iterator(); while (it.hasNext()) { it.next(); it.remove(); } } // String conversion /** * Returns a string representation of this collection. The string * representation consists of a list of the collection's elements in the * order they are returned by its iterator, enclosed in square brackets * (
"[]"). Adjacent elements are separated by the characters *
", " (comma and space). Elements are converted to strings as * by {@link String#valueOf(Object)}. * * @return a string representation of this collection */ public String toString() { Iterator
it = iterator(); if (! it.hasNext()) return "[]"; StringBuilder sb = new StringBuilder(); sb.append('['); for (;;) { E e = it.next(); sb.append(e == this ? "(this Collection)" : e); if (! it.hasNext()) return sb.append(']').toString(); sb.append(',').append(' '); } }}

4.2.三个层次在线程池体系中的运用

Java所有的线程池最顶层是一个Executor接口,其只有一个execute方法,用于执行所有的任务,java又提供了ExecutorService接口继承自Executor并且扩充了一下方法,在往下就是AbstractExecutorService这个抽象类,其实现了ExecutorService,最后就是ThreadPoolExecutor其继承自上面的抽象类,我们常使用的java线程池就是创建的这个类的实例。为了方便构造线程池,Java又提供了一个Executors工具类,它就是一个语法糖,为我们把各种不同的业务的线程池参数进行封装,进行new操作。

public static ExecutorService newFixedThreadPool(int nThreads) {        return new ThreadPoolExecutor(nThreads, nThreads,                                      0L, TimeUnit.MILLISECONDS,                                      new LinkedBlockingQueue
()); }

上面就是Executors.newFixedThreadPool()的源码,用来快速方便的构造固定数量线程的线程池。

 

你可能感兴趣的文章
C++默认参数
查看>>
正则表达式中有用但很少用的语法
查看>>
Vim 的 XML 文档编辑插件——xml.vim
查看>>
vim帮助文档无法跳转的问题
查看>>
vim常用快捷键及设置
查看>>
数据挖掘十大经典算法(6) PageRank
查看>>
数据挖掘十大经典算法(7) AdaBoost
查看>>
数据挖掘十大经典算法(9) 朴素贝叶斯分类器 Naive Bayes
查看>>
数据挖掘十大经典算法(10) CART: 分类与回归树
查看>>
初探数据挖掘中的十大经典算法
查看>>
android- ViewPager的跳转Fragment
查看>>
android-Banner控件的简单轮播图
查看>>
android-数据存入SP SP读取数据(简单案例)
查看>>
android-创建数据库存入数据,数据库数据的增删改查
查看>>
dccker-maven插件出现“Failed to execute goal com.spotifydocker-maven-plugin0.4.13....Permission den问题
查看>>
Java内存模型及其原理
查看>>
synchronized的原理及应用
查看>>
探索大数据基础设施容器化 | StartDT Tech Lab 04
查看>>
MFC——子窗口之间传递参数和调用函数
查看>>
Ubuntu18.04安装NVIDIA显卡驱动
查看>>