Java核心技术-集合

9.1 java集合框架

一 将集合的接口与实现分离

例如:队列接口的可能实现形式:

public interface Queue<E>

{

void add(E element);

E remove();

int size();

}

队列的两种实现形式:一种使用循环数组,一种是使用链表

*如果需要一个循环数组队列,就可以使用ArrayDeque类,如果需要一个链表队列,就直接使用LinkedList类,这个类实现了Queue接口。

一旦构建了集合就不需要知道究竟使用了哪种实现

使用接口类型存放集合的引用:

Queue<Customer> expressLane = new CircularArrayQueue<>(100);

expressLane.add(new Customer("tiffany"));

Queue<Customer> expressLane = new LinkedListQueue<>(100);

expressLane.add(new Customer("tiffany"));

循环数组是一个有界集合,如果程序中要收集的对象数量没有上限,就最好用链表来实现

二 Collecton接口(集合类的基本接口

public interface Collection<E>

{

boolean add(E element);//向集合中添加元素

Iterator<E> iterator();//用于返回一个实现了Iterator接口的对象

...

}

三 迭代器

public interface Iterator<E>

{

E next();//访问集合中的每个元素,迭代器越过下一个元素,并返回刚刚越过的那个元素的引用

boolean hasNext();//判断是否有下一个元素(存在可访问的元素),就返回true

void move();//删除上次调用next方法时返回的元素

default void forEachRemaining(Consumer<? super E> action);

}

“for each”循环是带有迭代器的循环,任何集合都可以使用它

元素被访问的顺序取决于集合类型

查找一个元素的唯一方法就是调用next

如果想要删除指定位置上的元素,仍然要越过这个元素,例如
 

Iterator<String> it = c.iterator();//调用迭代器

it.next();//越过第一个元素

it.move();//删除它

ps:如果调用remove 之前没有调用next将是不合法的。

四 泛型使用方法

Collection接口声明的一些方法:

int size()返回当前存储在集合中的元素个数

boolean isEmpty()如果集合中没有元素就返回true

boolean contains(Object obj)如果集合中包含了一个与obj相等的对象,就返回true

boolean containsAll(Collection<?> other)如果这个集合包含other集合中的所有元素,就返回true

boolean add(Object element)将一个元素添加到集合中

。。。

五 集合框架中的接口

集合有两个基本接口:Collection和Map

List集合:有序,访问方式:使用迭代器(顺序访问),随机访问

Set集合:无序,不允许增加重复元素

9.2 具体的集合

除以Map结尾的类之外,其他类都实现了Collection接口,而以Map结尾的类实现了Map接口。

一 链表(有序集合)

1 数组:优点:查询修改快 缺点:增删慢

 链表:优点:增删快 缺点:查询修改慢

2将三个元素中第二个元素删除

List<String> staff = new LinkedList<>();

staff.add("a");

staff.add("b");

staff.add("c");

Iterator iter = staff.iterator();

String first = iter.next();

String second = iter.next();

iter.remove();

3LinkedList.add:void类型,它假设添加操作总会改变链表(与Collection.add不同)

4用迭代器添加元素,迭代器总是在当前位置之前

5如果迭代器发现它的集合被另一个迭代器修改了,或是被该集合自身的方法修改了,就会抛出一个异常

List<String> list = ...;

ListIterator<String> iter1 = list.listIterator();

ListIterator<String> iter2 = list.listIterator();

iter1.next();

iter1.remove();

iter2.next();//error

由于iter2检测出这个链表被从外部修改了

为了避免这种异常,可以根据需要给容器附加许多迭代器,但是这些迭代器只能读取列表;另外再单独附加一个既能读又能写的迭代器

6使用链表的优点:尽可能地减少在列表中间插入或者删除所付出的代价

7如果需要对集合进行随机访问,就使用数组或ArrayList,而不要使用LinkedList

二 数组列表

两种访问元素的协议:

  1. 迭代器

  2. 使用get set方法随机地访问每个元素(不适用于链表)

ps:需要动态数组时使用ArrayList而不使用Vector的原因:Vector类的所有方法都是同步的,可以由两个线程安全滴访问一个Vector。但是如果由一个线程访问Vector,代码要在同步操作上耗费大量的时间。而ArrayList不是同步的。所以如果不需要同步时使用ArrayList,不要使用Vector

三 散列集(链表数组实现:因为数组是无序的)

散列表为每个对象计算一个整数,称为散列码。

2 补P170hashCode方法(定义在Object类):字符串的散列码是由内容导出的;而在StringBuffer类中没有定义hashCode方法,返回的是对象存储的地址

    如果重新定义equals方法,就必须重新定义hashCode方法,自己实现的hashCode方法应该与equals方法兼容,即如果a.equals(b)为true,a与b必须具有相同的散列码

3 散列冲突:桶被占满(散列值相同)

   桶数是指用于收集具有相同散列值的桶的数目,如果大致知道会有多少元素要插入到散列表中,就可以设置桶数,一般将桶数设置为预计元素个数的75%-150%,最好是素数

4 如果散列表太满,就需要对散列表再散列,一般填装因子大于0.75时就需要对散列表进行再散列

5 散列集的应用:HashSet类,访问顺序是随机的

四 树集(TreeSet)

1.树集是一个有序集合

2.补充:树的基本概念和存储:树是具有n个结点的集合,每个结点最多只有一个前驱,但可以有多个后继。(根结点无前驱)没有后继的结点称为叶子或终端结点。

一个结点的后继称为该结点的孩子,孩子部分顺序;一个结点的前驱称为该结点的双亲

树的表示方法:

  1. 广义表表示法

  2. 双亲表示法

  3. 左孩子右兄弟

  4. 孩子链表表示法

猜你喜欢

转载自blog.csdn.net/wo8vqj68/article/details/81164590
今日推荐