黑马程序员--Java基础--集合框架

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

集合框架
什么是集合呢?
其实集合和数组是一样的都是一种容器,用来存储数据的。
特点:
1.用来存储对象的。
2.集合的长度是可变的。
既然已经有了数组了,为什么还要集合呢?

集合和数组的区别:
1.集合存储的数据类型是引用数据类型(既对象),而不能存储基本数据类型,而数组只能存储同一种类型的数据,不但能存储引用数据类型,而且还可以存储基本数据类型。
2.集合的长度是可变的,而数组的长度是固定的。

集合类的关系图:

这里写图片描述


Collection接口下有两个常见的接口:
1.List接口。
2.Set接口。

这两个接口有什么区别呢?
1.List接口存储的元素是有序的,Set接口存储的元素是无序的。
2.List接口中的元素是可以重复的,因为有索引,而Set接口中的元素是不可以重复的,无索引。

这里所说的有序和无序指的是元素存入的顺序和取出的顺序不一致。
前面说过,想用一个体系中的功能,首先要了解最顶层的功能,创建最底层的对象,来使用该体系中的功能。

那么先了解下Collection接口中的方法。
1.添加:
add(Object); 添加一个元素。
addAll(Collection);添加一堆元素。

2.删除:
remove(Object);删除一个元素。注意:如果删除成功集合的长度会改变。
remove(Collection);删除一堆元素。删除的是和传入Collection集合元素相同的元素。
clear();将集合中的元素全部删除,清空集合。

3.判断:返回的都是boolean型。
contains(Object);判断集合中是否包含指定元素。
collectionAll(Collection);判断集合中是否包含指定Collection中相同的元素。
isEmpty();判断集合是否为空,也就是判断集合的长度是否为0。

4.获取:
size();判断集合的长度,也即是判断集合中有几个元素。

5.取交集:返回的是boolean类型的值。
retainAll(Collection); 保留当前集合中和指定Collection集合中相同的元素。如果两个集合元素相同返回false,如果retainAll()修改了当前集合,返回true。

6.获取集合中的元素:
iterator();迭代器。

7.将集合变成数组:
toArray();

重点是迭代器:Iterator接口。
作用:取出集合中的元素。

方法有:
1. hasNext();判断是否还有元素可以迭代,返回boolean型值。

2. next();返回迭代的下一个元素。

3. remove();从迭代其指向的Collection集合中移除迭代器返回的最后一个元素(可选操作)。

代码演示用迭代器的方法取出集合中元素。
代码:

import java.util.*;
class Test 
{
    public static void main(String[] args) 
    {
        ArrayList<String> al = new ArrayList<String>();//创建一个ArrayList集合,并指定集合中的元素类型为String。

        //添加以下四个元素。
        al.add("Hello");
        al.add("Java");
        al.add("Hello");
        al.add("World");

        //用迭代器的方法来取出集合中的元素。
        for(Iterator<String> it = al.iterator();it.hasNext();){
            System.out.println(it.next());//打印从集合中取出的元素。
        }
    }
}

List接口:存储的元素是有序的,且元素可以重复,每一个元素都有索引。

1.ArrayList:底层数据结构是数组,线程不同步,替代了Vector,优点:查询元素的速度非常快,添加和删除稍慢。

2.LinkedList:底层数据结构是链表,线程不同步,优点:添加和删除元素的速度非常快,查询速度稍慢。

3.Vector:底层数据结构是数组,线程同步,被ArrayList替代,无论是查询还是添加、删除都非常慢。

ArrayList特有方法:
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集合特有的迭代器。

重点:ListIterator接口。
这是List就集合的取出元素的特有的迭代器,不仅可以取出元素,而且还可以在取出元素的过程中对元素进行操作。如:添加、删除、修改、查询。

ListIterator 接口中特有的方法:
这里写图片描述

对于List集合判断元素是否相同用的都是equals方法,所以在实际开发中建议元素都要复写equals方法,建立元素自己的比较方法。

LinkedList特有的方法:
1.添加:
addFirst();在1.6版本后被offerFirst();替代。
addLast();在1.6版本后被offerLast();替代。

2.获取:
getFirst():获取链表中的第一个元素。如果链表为空,抛出NoSuchElementException;
getLast();
在jdk1.6以后。
peekFirst();获取链表中的第一个元素。如果链表为空,返回null。
peekLast();

3.删除:
removeFirst():获取链表中的第一个元素,但是会删除链表中的第一个元素。如果链表为空,抛出NoSuchElementException
removeLast();
在jdk1.6以后。
pollFirst();获取链表中的第一个元素,但是会删除链表中的第一个元素。如果链表为空,返回null。
pollLast();

Set接口:
简单来说Set接口中的方法和Collection接口中的方法是一致的。并且Set集合取出元素的方法只有一种就是迭代器。
1.HashSet:底层数据结构是哈希表。线程不同步,存储的元素是无序的,效率高,元素不可以重复。
LinkedHashSet:是HashSet的子类,元素是有序的。
2.TreeSet:底层数据结构是二叉树,是对Set集合中的元素进行指定顺序的排序,线程不同步。

那么HashSet集合是如何保证元素的唯一性呢?
1.先调用hashCode方法,判断元素的哈希值,如果哈希值不同则元素不同,如果相同用equals方法再次判断。
2.当元素的哈希值相同,则调用equals方法,再次判断元素本身是否相同,不同视为不同元素,在对象哈希值的基础上在顺延一次。如果相同视为同一个元素。
这样既保证了元素的唯一性,要提高了效率。

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

TreeSet:为了补足Set集合中元素无序的缺点。
它的作用是可以对元素进行指定顺序的排序。
排序的方式有两种:

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

注意:当两种方式都存在时,会以比较器为主。当然第二种方式更为灵活。
在进行比较时,如果判断元素不唯一,比如,同姓名,同年龄,才视为同一个人。
在判断时,需要分主要条件和次要条件,当主要条件相同时,再判断次要条件,按照次要条件排序。

Map集合:
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

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集合取出元素有两种方式:
1.keySet方法。可以将Map集合中的键取出并存到Set集合中,然后在对Set集合进行迭代,迭代完在通过Map集合的get方法即可获得相应的值。
代码演示:

import java.util.*;
class Test1 
{
    public static void main(String[] args) 
    {
        HashMap<Integer,String> hm = new HashMap<Integer,String>();//创建一个HashMap集合。
        //将以下元素添加到集合中。
        hm.put(2,"zhangsan");
        hm.put(5,"lisi");
        hm.put(6,"wangwu");
        hm.put(1,"zhouqi");

        //将集合中的键取出并存放到Set集合中。
        Set<Integer> s =hm.keySet();

        //用Set集合的迭代器等待方法去出去键,在用HashMap集合中的get方法来获取值。
        for(Iterator<Integer> it = s.iterator();it.hasNext();){
            int key = it.next();//获取键。
            String value =hm.get(key);//获取值。
            System.out.println(key+","+value);//打印键和值。
        }
    }
}

打印结果:
这里写图片描述

2.entrySet方法。将Map集合中的键和值的关系取出并存放的Set集合中,然后用Set集合的迭代器取出这些键和值的关系,并强转成Map.Entry类型,之后用这个类型的特有方法getKey和getValue方法获取到具体的键和值。
代码演示:
代码:

import java.util.*;
class Test1 
{
    public static void main(String[] args) 
    {
        HashMap<Integer,String> hm = new HashMap<Integer,String>();//创建一个HashMap集合,并定义键和值的类型。
        //将以下元素添加到集合中。
        hm.put(2,"zhangsan");
        hm.put(5,"lisi");
        hm.put(6,"wangwu");
        hm.put(1,"zhouqi");

        Set<Map.Entry<Integer,String>> ss = hm.entrySet();//获取HashMap集合中的键值对的关系(这种关系的类型是:Map.Entry类型),并存储到Set集合中。

        for(Iterator<Map.Entry<Integer,String>> it = ss.iterator();it.hasNext();){//用Set集合中的迭代器的方法遍历Set集合中键值对的关系。
            Map.Entry<Integer,String> m = (Map.Entry<Integer,String>)it.next();//将遍历的结果强转成Map.Entry类型。
            System.out.println(m.getKey()+",,,"+m.getValue());//调用Map.Entry的getKey和getValue方法获取到具体的键和值。
        }
    }
}

Collections:集合工具类。
它的出现给集合操作提供了更多的功能。 它的类不需要创建,全是静态的方法。提供了对集合的查找、排序、替换、线程安全化(将非同步的转换成同步的)等操作集合的方法。

Collection和Collections的区别:
Collections是java.util下的一个类,是真对集合类的一个工具类,全是静态的方法,包含了对集合的查找、排序、替换、线程安全化等操作。
Collection是java.util下的一个接口,是各种集合结构的父接口,继承了它的主要接口有:List和Set接口,是一个容器,用来存储对象的,提供了一些对集合的插入、删除、判断一个元素是否存在,遍历元素等方法。

再来讲一个工具类:Arrays。
这个工具类显然是对数组进行操作的工具类,包含的方法也都是静态的。
包括对数组的查找、插入、判断、复制、排序等操作。

里面有一个方法:asList方法。是将数组转换成List集合。

那么将数组转换成数组有什么好处呢?
将数组转换成集合,可以通过用List集合中的方法来操作数组中的元素。可以查找、判断是否存在、长度是否为空、返回指定位置的元素等操作,但是它有局限性。
局限性:就是数组的长度是固定的,不可以用集合的方法来进行对数组元素的删除和添加操作等一些会改变数组长度的方法,会报不支持操作异常(UnsupportedOperationException)。

值得注意的是:
如果数组中存储的是引用数据类型,直接作为集合的元素,可以直接用集合方法操作。
如果数组中存储的是基本数据类型,asList会将数组实体作为集合元素存在。

集合变数组:
用的是Collection接口中的方法:toArray();
如果给toArray传递的指定类型的数据长度小于了集合的size,那么toArray方法,会自定再创建一个该类型的数据,长度为集合的size。
如果传递的指定的类型的数组的长度大于了集合的size,那么toArray方法,就不会创建新数组,直接使用该数组即可,并将集合中的元素存储到数组中,其他为存储元素的位置默认值null。

将集合变成数组后有什么好处?
如果不想牵扯到对集合中元素进行增删操作可用此方法。
限定了对集合中的元素进行增删操作,只要获取这些元素即可。

静态导入:导入了类中的所有静态成员,简化静态成员的书写。
import static java.util.Collections.*; //导入了Collections类中的所有静态成员

练习:
需求:使用LinkedList模拟一个堆栈或者队列的数据结构。
堆栈:先进后出。如同一个杯子。
队列:先进先出。如同一个水管。

import java.util.*;
class LinkedListTest 
{
    public static void main(String[] args){
        //演示队列的数据结构。
        DuiLie dl = new DuiLie();

        //向队列中添加元素。
        dl.add("java01");
        dl.add("java02");
        dl.add("java03");
        dl.add("java04");

        //从队列中取出元素。

        sop("这是队列数据结构的:");
        for (;!dl.isEmpty() ; )
        {
            sop(dl.get());
        }

        //演示堆栈的数据结构。
        DuiZhan dz = new DuiZhan();

        //向堆栈中添加元素。
        dz.add("java100");
        dz.add("java200");
        dz.add("java300");
        dz.add("java400");

        sop("这是堆栈数据结构的:");
        //从堆栈中取出元素。
        for (;!dz.isEmpty() ; )
        {
            sop(dz.get());
        }

    }
    public static void sop(Object obj){
        System.out.println(obj);
    }

}
class DuiLie
{
    private LinkedList link;
    //建立对象时一初始化就产生一个LinkedList对象。这样做的目的是使该对象具有LinkedList数据结构。
    DuiLie(){           
        link = new LinkedList();
    }
    //提供一个添加元素的方法。
    public void add(Object obj){
        link.offerLast(obj);
    }
    //对外提供一个获取元素的方法。
    public Object get(){
        return link.pollFirst();
    }

    //对外提供一个判断该队列是否为空的方法。
    public boolean isEmpty(){
        return link.isEmpty();
    }
}
class DuiZhan
{
    private LinkedList link;
    //建立对象时一初始化就产生一个LinkedList对象。这样做的目的是使该对象具有LinkedList数据结构。
    DuiZhan(){              
        link = new LinkedList();
    }
    //对外部提供一个添加元素的方法。
    public void add(Object obj){
        link.offerFirst(obj);
    }
    //对外部提供一个获取元素的方法。
    public Object get(){
        return link.pollFirst();
    }

    //对外部提供一个判断堆栈是否为空的方法。
    public boolean isEmpty(){
        return link.isEmpty();
    }
}

总结:
使用集合的技巧:
1.看到Array就是数组结构,有角标,查询速度很快。

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

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

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

TreeSet集合比较的两种方式:
1.Comparable:覆盖compareTo方法;
2.Comparator:覆盖compare方法。
LinkedHashSet,LinkedHashMap:这两个集合可以保证哈希表有存入顺序和取出顺序一致,保证哈希表有序。

集合什么时候用?
当存储的是一个元素时,就用Collection。当存储对象之间存在着映射关系时,就使用Map集合。

保证唯一,就用Set。不保证唯一,就用List。

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值