黑马程序员_集合框架

---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------

集合框架

概述

集合类的由来:对象用于封装特有数据,如果对象的个数不确定,就是用集合容器进行存储。

集合的特点:

1. 用于存储对象的容器。

2. 集合的长度是可变的。

3. 不能存储基本数据类型。

 

体系&共性功能

框架顶层Collection接口:

1. 添加

boolean add(E e)

boolean addAll(Collection<? extends E> c)

 

2. 删除

void clear()

boolean remove(Object o)

boolean removeAll(Collection<?> c)

default boolean removeIf(Predicate<? super E> filter)

Removes all of the elements of this collection that satisfy the given  predicate

boolean retainAll(Collection<?> c)

Retains only the elements in this collection that are contained in the  specified collection (optional operation).

 

3. 判断

boolean contains(Object o)

boolean containsAll(Collection<?> c)

boolean equals(Object o)

boolean isEmpty()

 

4. 获取

Iterator<E> iterator取得迭代器

int size()

 

5. 其他

Object[] toArray()

<T> T[] toArray(T[] a)

......

迭代器

迭代器的使用:

例子:

Collection coll ...;

Iteraotor it = coll.iterator();

两种遍历方式:

1. while循环,循环结束后it还有效。

while (it.hasNext()) {

System.out.println(it.next());

}

 

2. for循环。循环结束后it失效。把it的生命周期限定在for循环内。实际开发中请使用这种方式。

for (Iterator it = coll.iterator(); it.hasNext(); ) {

System.out.println(it.next());

}

 

迭代器原理:

Iterator接口就是对所有的Collection容器进行元素取出的公共接口。

每一种容器都有一个实现Iterator接口的内部类

ListSet的特点

List有序(存入和取出的顺序一致)元素都有索引,元素可重复。

Set元素不能重复,无序。

List的常见方法

增删改查......

ListIterator listIterator()方法可以在遍历的时候做添加或删除元素。

 

 

List

|--Vector 内部是数组数据结构。是同步的(线程安全),效率低。几乎不用了。长度超出时,自动增加原来长度1倍。增删,查询都很慢。

|--ArrayList 内部是数组数据结构。是不同步的。替代了Vector。长度超出时,自动增加原长度50%。查询速度快。

|--LinkedList 内部是链表数据结构。是不同步的。增删元素的速度快。

数组和链表

ArrayList 查询快,增删慢。存储空间是连续的。

LinkedList 查询慢,增删快。

Vector集合

JDK1.0中的集合类。JDK1.2被添加到新增加的集合框架中。

Vector有自己特有的遗留方法。

如:addElement(E e) elements()等。

Enumeration接口:Vectorelements方法返回值,用于遍历。

boolean hasMoreElements()

E nextElement()

应该用Iterator来代替Enumeration

LindedList集合

public class LinkedList<E>

extends AbstractSequentialList<E>

implements List<E>, Deque<E>, Cloneable, Serializable

有所实现的接口的所有方法。

 

void addFirst(E e)

void addLast(E e)

 

removeFirst()

removeLast()

 

E getFirst() 获取但不移除。如果链表为空,则抛NoSuchElementException

E getLast()

 

 

......

 

面试题:使用LinkedList来模拟一个堆栈或队列数据结构。

堆栈,先进后出 FILO

队列,先进先出 FIFO

 

ArrayList集合

练习:去除一个ArrayList中的重复元素。

Set的常见方法

Set 元素不重复,无序。

Set接口中的方法和Collection一致。

Set

  |--HashSet

  |--TreeSet

HashSet集合

存储的元素为自定义对象的时候,如果元素需要按照自定义的规则来确定位置。那元素就得覆盖hashCode方法和equals方法

哈希表

HashSet集合数据结构是哈希表。存储元素的时候使用元素的hashCode方法来确定位置,如果位置相同(即哈希值相同)再使用equals()方法判断元素的内容是否相同

 

LinkedHashSet集合

具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。此实现与 HashSet 的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。

TreeSet集合

可以对Set集合中的元素进行排序,是不同步的。

判断元素唯一性的方式:根据比较方法的返回结果是否是0,是0表示是相同元素,不存。

TreeSet对元素进行排序的方式一:

让元素自身具备比较功能,元素需要实现Comparable接口,覆盖CompareTo方法。

 

如果不要按照对象中具备的自然顺序进行排序。如果对象中不具备自然排序。怎么办?

可以使用TreeSet集合的第二种排序方式:

让集合自身具备比较功能。定义一个类实现Comparator接口,覆盖compare方法。将该类作为参数传递给TreeSet集合的构造函数。

 

我自己的话说就是:

TreeSet中的元素是有顺序的,而顺序是通过一定的比较规则来确定的。有两种方式来确定比较规则:

1. 元素自身实现Comparable接口,覆盖ComparaTo方法。在CompareTo方法中定义比较规则。

2. 构造带比较器的TreeSet,即TreeSet(Comparator<? super E> comparator)。自定义一个类实现Comparator接口,覆盖的compate方法里定义比较规则,再把这个类的对象传给TreeSet构造器。

注:

1. 构造带比较器的TreeSet时,存到里面的元素可以不用实现Comparable接口。

2. 当两种方式都实现了的时候,以第二种方式为准。即当元素自身实现了Comparable接口,TreeSet又是带比较器构造的。则元素的顺序以比较器的规则为准。

3. 一般地,需要进行排序的对象都会实现Comparable接口。比如Java定义的类StringIntegerLong等。

4. 实际开发中,一般使用比较器。因为它可以自定义规则,更加灵活。

 

二叉树(红黑树)

 

 

 

Map集合

接口Map<K, V>。一次添加一对元素,Collection一次添加一个元素。

Map称为双列集合,Collection称为单列集合。

Map集合中存储的就是键值对。必须保证键的唯一性。

 

常用方法:

1. 添加。

V put(K key, V value)

将指定的值与此映射中的指定键关联(可选操作)。如果此映射以前包含一个该键的映射关系,则 用指定值替换旧值(当且仅当 m.containsKey(k) 返回 true 时,才能说映射 包含键 的映射关 系)。 

 

2. 删除。

void clear()

从此映射中移除所有映射关系(可选操作)。此调用返回后,该映射将为空。 

V remove(Object key)

如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。更确切地讲,如果此映射包含 从满足 (key==null ? k==null :key.equals(k)) 的键 到值 的映射关系,则移除该映射关系。(该 映射最多只能包含一个这样的映射关系。) 

 

返回此映射中以前关联该键的值,如果此映射不包含该键的映射关系,则返回 null。 

 

如果此映射允许 null 值,则返回 null 值并不一定 表示该映射不包含该键的映射关系;也可能该 映射将该键显示地映射到 null。 

 

调用返回后,此映射将不再包含指定键的映射关系。

 

 

3. 判断。

boolean containsKey(Object key)

如果此映射包含指定键的映射关系,则返回 true。

boolean containsValue(Object value)

如果此映射将一个或多个键映射到指定值,则返回 true。 

boolean isEmpty()

如果此映射未包含键-值映射关系,则返回 true。

boolean equals(Object o)

比较指定的对象与此映射是否相等。

 

4. 获取。

V get(Object key)

返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。  

int size()

返回此映射中的键-值映射关系数。如果该映射包含的元素大于 Integer.MAX_VALUE,则返回 Integer.MAX_VALUE。 

Set<Map.Entry<K,V>> entrySet()

返回此映射中包含的映射关系的 Set 视图。该 set 受映射支持,所以对映射的更改可在此 set 中反映出来,反之亦然。

Set<K> keySet()

返回此映射中包含的键的 Set 视图。

Collection<V> values()

返回此映射中包含的值的 Collection 视图。

 

 

 Map常用的子类

|--Hashtable 内部结构是哈希表,是同步的。不允许null作为键或值。

|--Properties 用来存储键值对型的配置文件信息。可以和IO技术相结合。

|--HashMap 内部结构是哈希表,不是同步的。允许null作为键或值。

|--TreeMap 内部结构是二叉树,不是同步的。可以对Map集合中键进行排序。

泛型

概述

泛型:JDK1.5出现的安全机制。

好处:1. 将运行时期的问题ClassCastException转移到变异时期。

      2. 避免了强制转换的麻烦。

<>:什么时候用?当操作的引用数据类型不确定的时候。就是用<>。将要操作的引用数据类型传入即可。其实<>就是一个用于接收具体引用数据类型的参数范围。

 

在程序中,只要用到了带有<>的类或者接口,就要明确传入的具体引用数据类型。

 

泛型技术是给编译器使用的技术,用于编译时期,确保对了类型的安全。

 

擦除&补偿

泛型的擦除:运行时,会将泛型去掉,生成的class文件是不带泛型的,这个称为泛型的擦除。

为什么擦除呢?为了兼容运行的类加载器。

 

泛型的补偿:在运行时,通过获取元素的类型进行转换动作。不用使用者再强制转换了。

 

在集合中的应用

泛型类

class Tool<T> {

}

 

JDK1.5后,使用泛型来接受类中要操作的引用数据类型。

泛型类。什么时候用?当类中操作的引用数据类型不确定的时候,就使用泛型来表示。

泛型方法

public <T> void show(T t) {

// ...

}

注意:

当方法是静态的,不能访问类上定义的泛型。如果静态方法要使用泛型,只能将泛型定义在方法上。

泛型接口

public class GenericDemo5 {

public static void main(String[] args) {

InterImpl in = new InterImpl();

in.show("abc");

InterImpl2<Integer> in2 = new InterImpl2<Integer>();

in2.show(3223);

}

}

 

/**

 * 将泛型定义在接口上。

 */

interface Inter<T> {

public void show(T t);

}

 

class InterImpl implements Inter<String> {

public void show(String s) {

System.out.println(s);

}

}

 

class InterImpl2<Q> implements Inter<Q> {

public void show(Q q) {

System.out.println(q);

}

}

 

泛型限定(上限 下限 通配符)

通配符?:当不知道类型且不需要对该类型进行操作的时候,可以使用通配符。

上限 <? extends Person> 接收Person类型或者Person的子类型对象。

下限 <? super Student>接收Student类型或者Student的父类型。

 

一般在定义存元素的方法的时候用上限,因为这样都是按照上限类型来运算的,不会出现类型安全隐患。

通常对集合中的元素进行取出操作时,可以使用下限。

 

 

集合的一些技巧

需要唯一吗?

需要:Set

需要指定顺序吗?

需要:TreeSet

不需要:HashSet

但是想要一个和存储顺序一致的顺序(有序):LinkedList

不需要:List

需要频繁增删吗?

需要:LinkedList

不需要:ArrayList

 

如何记住每一个容器的结构和所属的体系呢?

List

|--ArrayList

|--LinkedList

Set

|--HashSet

|--TreeSet

 

前缀名就是该集合的数据结构。

看到array,就要想到数组,就要想到查询快,有角标。

看到link就要想到链表,就要想到增删快,就要想到add get remove + first last的方法。

看到hash就要想到哈希表,就要想到唯一性,就要想到元素需要覆盖hashCode方法和equals方法。

看到tree就要想到二叉树,就要想到排序,就要想到两个接口ComparableComparator

而且这些常用的集合容器都是不同步的。

 

集合框架工具类

Collections

集合框架的工具类。里面的方法都是静态的。

 

Arrays

如果数组中的元素是对象,那么转成集合时,直接将数组中的元素作为集合中的元素进行集合存储;

如果数组中的元素是基本类型数值,那么会将该数组作为集合中的元素进行存储。

 

重点:List asList(数组)将数组转成集合。

好处:其实可以使用集合的方法操作数组中的元素。

注意:数组的长度是固定的,所以对于集合的增删方法是不可以使用的

否则会发生UnsupportedOperationException

集合转数组的toArray()方法使用

集合转成数组呢?

使用的就是Collection接口中的toArray方法。

集合转成数组:可以对集合中的元素操作的方法进行限定,但不允许对其进行增删。

 

toArray方法需要传入一个指定类型的数组。

长度该如何定义呢?

如果长度小于集合的size,那么该方法会创建一个同类型并和集合相同size的数组。

如果长度大于集合的size,那么该方法就会使用指定的数组,存储集合中的元素,其他位置默认为

null

所以建议,最后长度就指定为,集合的size

 

---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值