java基础-集合框架

集合:面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。

集合框架: Java集合框架是指java的集合类。Collection 接口是一组允许重复的对象。Set 接口继承 Collection,但不允许重复,使用自己内部的一个排列机制。 List 接口继承 Collection,允许重复,以元素安插的次序来放置元素,不会重新排列。Map接口是一组成对的键-值对象,即所持有的是key-value pairs。Map中不能有重复的key。拥有自己的内部排列机制。

 

数组和集合类同是容器,有何不同?

 数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。

集合类的特点集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。

 

       Java集合框架结构图

 

 

 1、Collection接口及其实现类

 

 Collection: 

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

    |--ArrayList:底层的数据结构是数组,线程不同步,ArrayList替代了Vector,查询元素的速度非常快。 

|--LinkedList:底层的数据结构是链表,线程不同步,增删元素的速度非常快。 

|--Vector:底层的数据结构就是数组,线程同步的,Vector无论查询和增删都巨慢。

|--Set:无序(存入和取出顺序有可能不一致),不可以存储重复元素。必须保证元素唯一性。

|--HashSet:底层数据结构是哈希表,线程是不同步的。无序,高效; 

 |--LinkedHashSet:有序,hashset的子类。 

    |-- SortedSet [I]

|--TreeSet:对Set集合中的元素的进行指定顺序的排序。不同步。TreeSet底层的数据结构就是二叉树。

Map:

|--Hashtable:底层是哈希表数据结构,是线程同步的。不可以存储null键,null值。

 |--HashMap:底层是哈希表数据结构,是线程不同步的。可以存储null键,null值。替代了Hashtable. 

|--TreeMap:底层是二叉树结构,可以对map集合中的键进行指定顺序的排序。


    是否有序 是否允许元素重复
Collection
List
Set AbstractSet
  HashSet
  TreeSet 是(用二叉排序树)
Map AbstractMap 使用key-value来映射和存储数据,key必须唯一,value可以重复
  HashMap
  TreeMap 是(用二叉排序树)

Collection接口
    Collection是最基本的集合接口,一个Collection代表一组Object的集合,这些Object被称作Collection的元素。

1,添加: 

add(object):添加一个元素 

addAll(Collection) :添加一个集合中的所有元素。

 2,删除: 

clear():将集合中的元素全删除,清空集合。 

remove(obj) :删除集合中指定的对象。注意:删除成功,集合的长度会改变。

 removeAll(collection) :删除部分元素。部分元素和传入Collection一致。

 3,判断: 

boolean contains(obj) :集合中是否包含指定元素 。 

boolean containsAll(Collection) :集合中是否包含指定的多个元素。

 boolean isEmpty():集合中是否有元素。

  4,获取: 

int size():集合中有几个元素。

 5,取交集: 

boolean  retainAll(Collection) :对当前集合中保留和指定集合中的相同的元素。如果两个集合元素相同,返回flase;如果retainAll修改了当前集合,返回true。

6,获取集合中所有元素:

 Iterator  iterator():迭代器 

7,将集合变成数组:

 toArray(); 

下面是一个集合的实例:

复制代码
import java.util.ArrayList;

import java.util.Collection;

import java.util.HashSet;

import java.util.Iterator;

 

public class TestCollection

{

    public static void main(String[] args)

    {

        Collection  c = new ArrayList  ();

        Collection  c1 = new ArrayList  ();

        c.add("wk");  //添加元素

        c.add(6);//虽然集合里不能放基本类型的值,但Java支持自动装箱

        c.add('a');

        c.add("heima");

       

        c1.add("heima");  //添加元素

        c1.add("wk");  //添加元素

       

        c.addAll(c1);// 添加整个集合

       

        System.out.println("c中元素个数为:" + c.size());      

        c.remove(6); //删除指定元素

       

        System.out.println("c中元素个数为:" + c.size());

       

       if( c.contains("wk")){//判断是否包含指定字符串

             System.out.println("c中包含元素'wk'");

       }else{

             System.out.println("c中不包含元素'wk'");

       }

 

        System.out.println("c集合是否完全包含cl集合?" + c.containsAll(c1));//判断c是否包含c1

       

        System.out.println("c集合的元素有:" );

 

        Iterator it = c.iterator(); // 获得一个迭代子 ,用迭代的方法获取集合中的元素

        while(it.hasNext()) {

           Object obj = it.next(); // 得到下一个元素

           System.out.println(  obj);

        }

        System.out.println("c集合的元素:" + c);//直接打印集合c

 

       

        c.clear();//删除c集合里所有元素

 

        System.out.println("c集合的元素:" + c);

 

       

    }

}    
复制代码

 

 

 

List接口

    List继承自Collection接口。List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。

    跟Set集合不同的是,List允许有重复元素。对于满足e1.equals(e2)条件的e1与e2对象元素,可以同时存在于List集合中。当然,也有List的实现类不允许重复元素的存在。

除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个 ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素, 还能向前或向后遍历。

 1,添加: 

add(index,element) :在指定的索引位插入元素。 

addAll(index,collection) :在指定的索引位插入一堆元素。 

2,删除: 

remove(index) :删除指定索引位的元素。 返回被删的元素。 

3,获取: 

Object get(index) :通过索引获取指定元素。 

int indexOf(obj) :获取指定元素第一次出现的索引位,如果该元素不存在返回-1;  

 所以,可以通过-1,判断一个元素是否存在。 

int lastIndexOf(Object o) :反向索引指定元素的位置。

 List subList(start,end) :获取子列表。 

4,修改: 

Object set(index,element) :对指定索引位进行元素的修改。 

5,获取所有元素: 

ListIterator listIterator():list集合特有的迭代器。

 

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 it = list.iterator;  

 

 

 

实现List接口的常用类有LinkedList,ArrayList,Vector和Stack。

LinkedList类

    LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert方法在 LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。

    注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:

List list = Collections.synchronizedList(new LinkedList(...)); 

 

ArrayList类

    ArrayList实现了可变大小的数组。它允许所有元素,包括null。ArrayList没有同步。

size,isEmpty,get,set方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。

    每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并 没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。

    和LinkedList一样,ArrayList也是非同步的(unsynchronized)。

 

Vector类

    Vector非常类似ArrayList,但是Vector是同步的。由Vector创建的Iterator,虽然和ArrayList创建的 Iterator是同一接口,但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例如,添加或删除了一些元素),这时调用Iterator的方法时将抛出ConcurrentModificationException,因此必须捕获该异常。

 

Stack 类

Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop方 法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。

 

 

 

Set接口

    Set继承自Collection接口。Set是一种不能包含有重复元素的集合,即Set集合里任意两个元素e1和e2都满足e1.equals(e2)==false条件,Set最多有一个null元素。

     因为Set的这个制约,在使用Set集合的时候,应该注意:

    1,为Set集合里的元素的实现类要实现一个有效的equals(Object)方法。

    2,对Set的构造函数,传入的Collection参数不能包含重复的元素。

 

请注意:必须小心操作可变对象(Mutable Object)。如果一个Set中的可变元素改变了自身状态导致Object.equals(Object)=true将导致一些问题。

 

实现List接口的常用类有HashSetTreeSet

 

HashSet类

    此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证集合的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。

HashSet不是同步的,需要用以下语句来进行S同步转换:
            Set s = Collections.synchronizedSet(new 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集合的构造函数。 

第二种方式较为灵活。 

 


 

Map接口

    Map没有继承Collection接口。也就是说Map和Collection是2种不同的集合。Collection可以看作是(value)的集合,而Map可以看作是(key,value)的集合。要保证map集合中键的唯一性

Map接口由Map的内容提供3种类型的集合视图,一组key集合,一组value集合,或者一组key-value映射关系的集合。

 

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

Collection一次存一个元素;Map一次存一对元素。

Collection是单列集合;Map是双列集合。 

Map中的存储的一对元素:一个是键,一个是值,键与值之间有对应(映射)关系。

 

Map中的方法有

 1,添加。 

 put(key,value):当存储的键相同时,新的值会替换老的值,并将老值返回。如果键没有重复,返回null。

 void putAll(Map);

 2,删除。 

void clear():清空 

value remove(key) :删除指定键。 

3,判断。 

boolean isEmpty(): 

boolean containsKey(key):是否包含key 

boolean containsValue(value) :是否包含value 

4,取出。 

int size():返回长度 value

 get(key) :通过指定键获取对应的值。如果返回null,可以判断该键不存在。当然有特殊情况,就是在hashmap集合中,是可以存储null键null值的。

 Collection values():获取map集合中的所有的值。 

 

5,想要获取map中的所有元素: 

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

把map集合转成set的方法: 

Set keySet(); 

Set entrySet();//取的是键和值的映射关系。 

Entry就是Map接口中的内部接口; 

为什么要定义在map内部呢?entry是访问键值关系的入口,是map的入口,访问的是map中的键值对。

 

取出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()); 

 

 

实现List接口的常用类有HashtableHashMap,WeakHashMap

 

 

Hashtable类

    Hashtable继承Map接口,实现一个key-value映射的哈希表。任何非空(non-null)的对象都可作为key或者value。

    添加数据使用put(key, value),取出数据使用get(key),这两个基本操作的时间开销为常数。

Hashtable 通过initial capacity和load factor两个参数调整性能。通常缺省的load factor 0.75较好地实现了时间和空间的均衡。增大load factor可以节省空间但相应的查找时间将增大,这会影响像get和put这样的操作。

使用Hashtable的简单示例如下,将1,2,3放到Hashtable中,他们的key分别是”one”,”two”,”three”:

Hashtable numbers = new Hashtable(); 

numbers.put("one", new Integer(1)); 

numbers.put("two", new Integer(2)); 

numbers.put("three", new Integer(3)); 

要取出一个数,比如2,用相应的key:

Integer n = (Integer)numbers.get("two"); 

System.out.println("two =" + n); 

    由于作为key的对象将通过计算其散列函数来确定与之对应的value的位置,因此任何作为key的对象都必须实现hashCode和equals方 法。hashCode和equals方法继承自根类Object,如果你用自定义的类当作key的话,要相当小心,按照散列函数的定义,如果两个对象相 同,即obj1.equals(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,则它们的hashCode不一定不同,如 果两个不同对象的hashCode相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()方法,能加快哈希 表的操作。

    如果相同的对象有不同的hashCode,对哈希表的操作会出现意想不到的结果(期待的get方法返回null),要避免这种问题,只需要牢记一条:要同时复写equals方法和hashCode方法,而不要只写其中一个。

    Hashtable是同步的。

 

HashMap类

    HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key。,但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap 的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低。

 

WeakHashMap类

    WeakHashMap是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收。

 

使用集合的技巧: 

看到Array就是数组结构,有角标,查询速度很快。 

看到link就是链表结构:增删速度快,而且有特有方法。addFirst; addLast; removeFirst(); removeLast(); getFirst();getLast(); 

看到hash就是哈希表,就要想要哈希值,就要想到唯一性,就要想到存入到该结构的中的元素必须覆盖hashCode,equals方法。 

看到tree就是二叉树,就要想到排序,就想要用到比较。

要注意的问题:

1、Collection没有get()方法来取得某个元素。只能通过iterator()遍历元素。

2、Set和Collection拥有一模一样的接口。

3、List,可以通过get()方法来一次取出一个元素。使用数字来选择一堆对象中的一个,get(0)...。(add/get)

4、一般使用ArrayList。用LinkedList构造堆栈stack、队列queue。

5、Map用 put(k,v) / get(k),还可以使用containsKey()/containsValue()来检查其中是否含有某个key/value。

      HashMap会利用对象的hashCode来快速找到key。

 

6、Map中元素,可以将key序列、value序列单独抽取出来。

使用keySet()抽取key序列,将map中的所有keys生成一个Set。

使用values()抽取value序列,将map中的所有values生成一个Collection。

为什么一个生成Set,一个生成Collection?那是因为,key总是独一无二的,value允许重复。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值