Java学习笔记07 集合框架

1.概述

集合框架是用于存储数据的容器。常用的集合框架:
这里写图片描述

特点:

  1. 对象封装数据,对象多了也需要存储。集合用于存储对象。
  2. 对象的个数确定可以使用数组,但是不确定怎么办?可以用集合。因为集合是可变长度的。

集合和数组的区别:

  1. 数组是固定长度的;集合可变长度的。
  2. 数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型,集合中存储的都是数据的引用。
  3. 数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。

数据结构:
就是容器中存储数据的方式。对于集合容器,有很多种。因为每一个容器的自身特点不同,其实原理在于每个容器的内部数据结构不同。

集合容器在不断向上抽取过程中。出现了集合体系
在使用一个体系时,原则:参阅顶层内容。建立底层对象。

2.Collection接口

Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。此接口通常用来传递collection,并在需要最大普遍性的地方操作这些 collection。

Collection:
|–List:有序(存入集合的顺序和取出的顺序一致),元素都有索引,可以重复。
|–Set:无序(存入和取出的顺序有可能不一致),不可以存储重复元素,必须保证元素的唯一性。

常用的方法:

1 . 添加

boolean add(E e);//确保此 collection 包含指定的元素(可选操作)。 

boolean addAll(Collection<? extends E> c);//将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。 

2 . 删除

void clear();//移除此 collection 中的所有元素(可选操作)。 

boolean remove(Object o);//从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。 

boolean removeAll(Collection<?> c);//移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。 

3 . 判断

boolean contains(Object o);//如果此 collection 包含指定的元素,则返回 true。 

boolean containsAll(Collection<?> c);//如果此 collection 包含指定 collection 中的所有元素,则返回 true。 

boolean isEmpty();//如果此 collection 不包含元素,则返回 true。 

4 . 获取

int size();//返回此 collection 中的元素数。 

5 . 取交集

boolean retainAll(Collection<?> c);//仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。 

6 . 获取集合元素

Iterator<E> iterator();//返回在此 collection 的元素上进行迭代的迭代器。 

7 . 将集合变成数组

Object[] toArray(); //返回包含此 collection 中所有元素的数组。 

3.Iterator接口

对 collection 进行迭代的迭代器,用于取集合中的元素。迭代器取代了 Java Collections Framework 中的 Enumeration。迭代器与枚举有两点不同:

  • 迭代器允许调用者利用定义良好的语义在迭代期间从迭代器所指向的collection 移除元素。
  • 方法名称得到了改进。

迭代器的方法有:

boolean hasNext();//如果仍有元素可以迭代,则返回 true。 

E next();//返回迭代的下一个元素。 

void remove();//从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。

每一个集合都有自己的数据结构,都有特定的取出自己内部元素的方式。为了便于操作所有的容器,取出元素。将容器内部的取出方式按照一个统一的规则向外提供,这个规则就是Iterator接口

也就说,只要通过该接口就可以取出Collection集合中的元素,至于每一个具体的容器依据自己的数据结构,如何实现的具体取出细节,这个不用关心,这样就降低了取出元素和具体集合的耦合性。

Iterator it = coll.iterator();//获取容器中的迭代器对象。

对象是是什么不重要。这对象肯定符合一个规则Iterator接口。
代码示例:

public static void main(String[] args) 
{
    Collection coll = new ArrayList();
    coll.add("abc0");
    coll.add("abc1");
    coll.add("abc2");

    /*方式1*/
    Iterator it = coll.iterator();
    while(it.hasNext())
    {
        System.out.println(it.next());
    }

    /*方式2  常用用此种方式*/
    for(Iterator it = coll.iterator();it.hasNext(); )
    {
        System.out.println(it.next());
    }
}

4.List接口

有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。

List:有序(元素存入集合的顺序和取出的顺序一致),元素都有索引。元素可以重复。
|–ArrayList:底层的数据结构是数组,线程不同步,ArrayList替代了Vector,查询元素的速度非常快。
|–LinkedList:底层的数据结构是链表,线程不同步,增删元素的速度非常快。
|–Vector:底层的数据结构就是数组,线程同步的,Vector无论查询和增删都很慢。

List接口的常用方法:

1 . 添加:

boolean add(E e);//向列表的尾部添加指定的元素(可选操作)。 

boolean addAll(Collection<? extends E> c);//添加指定 collection 中的所有元素到此列表的结尾,顺序是指定 collection 的迭代器返回这些元素的顺序(可选操作)。 

2 . 删除:

boolean remove(Object o);//从此列表中移除第一次出现的指定元素(如果存在)(可选操作)。 

3 . 获取:

E get(int index);//返回列表中指定位置的元素。 

int indexOf(Object o);//返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。 

int lastIndexOf(Object o);//返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。 

List<E> subList(int fromIndex, int toIndex);//返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。 

4 . 修改:

 E set(int index, E element);//用指定元素替换列表中指定位置的元素(可选操作)。 

5 . 获取所有元素:

ListIterator<E> listIterator();//返回此列表元素的列表迭代器(按适当顺序)。 

List集合因为有角标,因此有自己遍历元素的方式:

for(int x=0; x<list.size(); x++)
{
    sop("get:"+list.get(x));
}

在进行list列表元素迭代的时候,如果想要在迭代过程中,想要对元素进行操作的时候,比如满足条件添加新元素。会产生ConcurrentModificationException并发修改异常

导致的原因是:
集合引用和迭代器引用在同时操作元素,通过集合获取到对应的迭代器后,在迭代中,进行集合引用的元素添加,迭代器并不知道,所以会出现异常情况。

如何解决呢?
既然是在迭代中对元素进行操作,找迭代器的方法最为合适.可是Iterator中只有hasNext,next,remove方法.通过查阅的它的子接口,ListIterator,发现该列表迭代器接口具备了对元素的增、删、改、查的动作。

ListIterator是List集合特有的迭代器。

ListIterator it = list.listIterator;//取代Iterator

可变长度数组的原理:
当元素超出数组长度,会产生一个新数组,将原数组的数据复制到新数组中,再将新的元素添加到新数组中。

  • ArrayList:是按照原数组的50%延长。构造一个初始容量为 10 的空列表。
  • Vector:是按照原数组的100%延长

注意:对于list集合,底层判断元素是否相同,其实用的是元素自身的equals方法完成的。所以建议元素都要复写equals方法,建立元素对象自己的比较相同的条件依据。

5.Set接口

一个不包含重复元素的 collection。更确切地讲,set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学上的 set 抽象。

Set接口中的方法和Collection中方法一致的。Set接口取出方式只有迭代器
|–HashSet:底层数据结构是哈希表,线程是不同步的。无序,高效;
|—-LinkedHashSet:有序,hashset的子类。
|–TreeSet:对Set集合中的元素的进行指定顺序的排序。不同步。TreeSet底层的数据结构就是二叉树。

HashSet:
HashSet集合保证元素唯一性:通过元素的hashCode方法和equals方法完成的。

  • 如果hashCode值相同,继续判断元素的equals是否为true。如果为true,那么视为相同元素,不存。如果为false,那么存储。
  • 如果hashCode值不同,那么不判断equals,从而提高对象比较的速度。

哈希表的原理:

  1. 对对象元素中的关键字(对象中的特有数据),进行哈希算法的运算,并得出一个具体的算法值,这个值称为哈希值。
  2. 哈希值就是这个元素的位置。
  3. 如果哈希值出现冲突,再次判断这个关键字对应的对象是否相同。如果对象相同,就不存储,因为元素重复。如果对象不同,就存储,在原来对象的哈希值基础 +1顺延。
  4. 存储哈希值的结构,我们称为哈希表。
  5. 既然哈希表是根据哈希值存储的,为了提高效率,最好保证对象的关键字是唯一的。这样可以尽量少的判断关键字对应的对象是否相同,提高了哈希表的操作效率。

ArrayList集合判断元素是否存在或者删元素,底层依据都是equals方法。
HashSet集合判断元素是否存在或者删除元素,底层依据的是hashCode方法和equals方法。

TreeSet:
用于对Set集合进行元素的指定顺序排序,排序需要依据元素自身具备的比较性。如果元素不具备比较性,在运行时会发生ClassCastException异常。所以需要元素实现Comparable接口,强制让元素具备比较性,复写compareTo方法。依据compareTo方法的返回值,确定元素在TreeSet数据结构中的位置。

TreeSet方法保证元素唯一性的方式:就是参考比较方法的结果是否为0,如果return 0,视为两个对象重复,不存。

注意:在进行比较时,如果判断元素不唯一,比如,同姓名,同年龄,才视为同一个人。在判断时,需要分主要条件和次要条件,当主要条件相同时,再判断次要条件,按照次要条件排序。

TreeSet集合排序有两种方式,Comparable和Comparator区别:

  1. 让元素自身具备比较性,需要元素对象实现Comparable接口,覆盖compareTo方法。

  2. 让集合自身具备比较性,需要定义一个实现了Comparator接口的比较器,并覆盖compare方法,并将该类对象作为实际参数传递给TreeSet集合的构造函数。

第二种方式较为灵活。

6.Map集合

将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。

常用子类:

  • Hashtable:底层是哈希表数据结构,是线程同步的。不可以存储null键,null值。
  • HashMap:底层是哈希表数据结构,是线程不同步的。可以存储null键,null值。替代了Hashtable.
  • TreeMap:底层是二叉树结构,可以对map集合中的键进行指定顺序的排序。

Map集合存储和Collection有着很大不同:

  • Collection一次存一个元素,Map一次存一对元素。
  • Collection是单列集合,Map是双列集合。

Map中的存储的一对元素:一个是键,一个是值,键与值之间有对应(映射)关系。要保证map集合中键的唯一性

常用方法:

1 . 添加。

V put(K key, V value) ;//将指定的值与此映射中的指定键关联(可选操作)。

void putAll(Map<? extends K,? extends V> m);//从指定映射中将所有映射关系复制到此映射中(可选操作)。 

2 . 删除。

void clear();//从此映射中移除所有映射关系(可选操作)。 

V remove(Object key);//如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。 

3 . 判断。

boolean isEmpty();//如果此映射未包含键-值映射关系,则返回 true。 

boolean containsKey(Object key);//如果此映射包含指定键的映射关系,则返回 true。 

boolean containsValue(Object value);//如果此映射将一个或多个键映射到指定值,则返回 true。 

4 . 取出。

int size();//返回此映射中的键-值映射关系数。 

V get(Object key);//返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。注意:在hashmap集合中,是可以存储null键null值的。

Collection<V> values();//返回此映射中包含的值的 Collection 视图。 

5 . 获取map中的所有元素:
map中是没有迭代器的,collection具备迭代器,只要将map集合转成Set集合,可以使用迭代器了。之所以转成set,是因为map集合具备着键的唯一性,其实set集合就来自于map,set集合底层其实用的就是map的方法。

把map集合转成set的方法:

Set<K> keySet();//返回此映射中包含的键的 Set 视图。

Set<Map.Entry<K,V>> entrySet();//返回此映射中包含的映射关系的 Set 视图。 

取出map集合中所有元素的方式一:keySet()方法。
可以将map集合中的键都取出存放到set集合中。对set集合进行迭代。迭代完成,再通过get方法对获取到的键进行值的获取。代码如下:

Set keySet = map.keySet();
Iterator it = keySet.iterator();
while(it.hasNext()) 
{
    Object key = it.next();
    Object value = map.get(key);
    System.out.println(key+":"+value);
}

取出map集合中所有元素的方式二:entrySet()方法。

Set entrySet = map.entrySet();
Iterator it = entrySet.iterator();
while(it.hasNext()) 
{
    Map.Entry  me = (Map.Entry)it.next();
    System.out.println(me.getKey()+"::::"+me.getValue());
}

集合的选择:
当存储的是一个元素时,就用Collection。当存储对象之间存在着映射关系时,就使用Map集合。保证唯一,就用Set。不保证唯一,就用List。

7.Collections

此类完全由在 collection 上进行操作或返回 collection 的静态方法组成。它包含在 collection 上操作的多态算法,即“包装器”,包装器返回由指定 collection。支持的新 collection,以及少数其他内容。

常用方法:

1 . 排序

static <T extends Comparable<? super T>> void sort(List<T> list);//根据元素的自然顺序 对指定列表按升序进行排序。 

static <T> void sort(List<T> list, Comparator<? super T> c);//根据指定比较器产生的顺序对指定列表进行排序。 

如list为一个元素为String的列表,则可以通过下面的代码进行按照默认顺序排序和按照长度排序:

Collections.sort(list);//对list的元素进行自然顺序的排序
Collections.sort(list, new ComparatorByLen());//使用自定义的比较器进行排序。
class ComparatorByLen implements Comparator<String>
{
    public int compare(String s1, String s2)
    {
        int tmp = s1.length() - s2.length();
        if(tmp == 0)
        {
            return s1.compareTo(s2);
        }
        else
        {
            retrun tmp;
        }
    }
}

2 . 查找

static <T extends Object & Comparable<? super T>> 
T max(Collection<? extends T> coll);//根据元素的自然顺序,返回给定collection 的最大元素。 

static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp);//根据指定比较器产生的顺序,返回给定 collection 的最大元素。 

static <T extends Object & Comparable<? super T>> 
T min(Collection<? extends T> coll);//根据元素的自然顺序 返回给定 collection 的最小元素。 

static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp);//根据指定比较器产生的顺序,返回给定 collection 的最小元素。 

static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key);//使用二分搜索法搜索指定列表,以获得指定对象。 

static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c);//使用二分搜索法搜索指定列表,以获得指定对象。 

如:

Collections.max(list);返回list中字典顺序最大的元素。
int index = Collections.binarySearch(list,"abc");//二分查找,返回角标。

3 . 生成逆向比较器

static <T> Comparator<T> reverseOrder();//返回一个比较器,它强行逆转实现了 Comparable 接口的对象 collection 的自然顺序。 

static <T> Comparator<T> reverseOrder(Comparator<T> cmp);//返回一个比较器,它强行逆转指定比较器的顺序。 

和sort结合可以对List进行逆向的排序。

4 . 随机排序

static void shuffle(List<?> list);//使用默认随机源对指定列表进行置换。 

static void shuffle(List<?> list, Random rnd);//使用指定的随机源对指定列表进行置换。 
  1. 将非同步集合转化为同步集合
static <T> Collection<T> synchronizedCollection(Collection<T> c);//返回指定 collection 支持的同步(线程安全的)collection。 

static <T> List<T> synchronizedList(List<T> list);//返回指定列表支持的同步(线程安全的)列表。 

static <K,V> Map<K,V> synchronizedMap(Map<K,V> m);//返回由指定映射支持的同步(线程安全的)映射。 

static <T> Set<T> synchronizedSet(Set<T> s);//返回指定 set 支持的同步(线程安全的)set。 

static <K,V> SortedMap<K,V>synchronizedSortedMap(SortedMap<K,V> m);//返回指定有序映射支持的同步(线程安全的)有序映射。 

static <T> SortedSet<T>synchronizedSortedSet(SortedSet<T> s);//返回指定有序 set 支持的同步(线程安全的)有序 set。 

原理:定义一个类,将集合所有的方法加同一把锁后返回。

Collection 和 Collections的区别:

  • Collections是个java.util下的类,是针对集合类的一个工具类,提供一系列静态方法,实现对集合的查找、排序、替换、线程安全化(将非同步的集合转换成同步的)等操作。

  • Collection是个java.util下的接口,它是各种集合结构的父接口,继承于它的接口主要有Set和List,提供了关于集合的一些操作,如插入、删除、判断一个元素是否其成员、遍历等。

8.Arrays

此类包含用来操作数组(比如排序和搜索)的各种方法。此类还包含一个允许将数组作为列表来查看的静态工厂。

asList方法:

static <T> List<T> asList(T... a);//返回一个受指定数组支持的固定大小的列表。 

将数组转换成list集合:

String[] arr = {"aaa","bbb","ccc"};
List<String> list = Arrays.asList(arr);//将arr数组转成list集合。

将数组转换成集合的好处是:

  1. 用aslist方法,将数组变成集合。可以通过list集合中的方法来操作数组中的元素:isEmpty()、contains、indexOf、set。
    注意(局限性):数组是固定长度,不可以使用集合对象增加或者删除等,会改变数组长度的功能方法。比如add、remove、clear。(会报不支持操作异常UnsupportedOperationException)。

  2. 如果数组中存储的引用数据类型,直接作为集合的元素可以直接用集合方法操作。

  3. 如果数组中存储的是基本数据类型,asList会将数组实体作为集合元素存在。

集合变数组:
用的是Collection接口中的方法:toArray

Object[] toArray();//返回包含此 collection 中所有元素的数组。 

<T> T[] toArray(T[] a);//返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。 
  • 如果给toArray传递的指定类型的数组长度小于了集合的size,那么toArray方法,会自定再创建一个该类型的数组,长度为集合的size。

  • 如果传递的指定的类型的数组的长度大于了集合的size,那么toArray方法就直接将集合中的元素存储到数组中,数组中其他存储元素的位置默认值null。

所以,在传递指定类型数组时,最好的方式就是指定的长度和size相等的数组。

将集合变成数组的好处:
限定了对集合中的元素进行增删操作,只要获取这些元素即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值