容器集合(集合的进阶,Collection,List,Set,Map,Map集合的综合使用--斗地主案列,并发修改异常,列表迭代器,Java面试中几个集合面试题)

目录

集合的体系结构

Collection集合:

collection集合的常用方法:

List集合:

List集合特有的方法:

ArrayList集合:

LinkedList集合:

 Set集合:

HashSet集合:

HashSet保证元素唯一性源码分析:

TreeSet集合:

Map集合:

HashMap集合:

Map集合的遍历方式:

Map集合的综合使用--斗地主案列:

并发修改异常:

列表迭代器:

Java面试中几个集合面试题

ArrayList和LinkedList有何区别?

Set和List的区别

HaspMap与TreeMap的区别:

Collection和Collections的区别


集合的体系结构

我们先来了解下,集合类的特点:

提供一种存储空间可变的存储模型,存储的数据容量可以随时发生改变。

集合类的体系图:

通过图,我们可以看到:

Collection集合:

Collection集合 是单例集合的顶层接口。但是,JDK不提供此接口的任何直接实现,它提供更具体的子接口(如Set和List)实现,所以可以用多态的方式以及具体的实现类如:ArrayList,LinkedList, TreeSet,HashSet等来创建Collection对象。

比如:Collection<String> c = new ArrayList() ;

collection集合的常用方法:

  

上面是博主对 collection集合的常用方法的一些展示,创建集合的时候以多态的形式创建,只要记住了常用的方法,使用起来还是很简单的。

Collection 接口有两个子接口:

List(列表)

Set(集)

List集合:

List集合的特点:有索引,可以存储重复的元素,元素有序

怎么来理解List集合的这些特点呢?我们一起来看看:

其实,List集合的底层代码是 数组,所以,List在存取数据的时候,是根据数组的特性来实现的。

我们知道,数组在存储数据的时候,会先分配一些空间用来存储数据,通常,数据是依次存入的,所以数据的位置有先后顺序,就类似于索引,这样我们可以通过数据的下标找到相应的元素。

在存储数据时,因为没有判断和限定数据,所以数据在存入时是可以重复的

所以,相应的,List集合也遵循了这些特点。

List集合特有的方法:

 这些方法和Collection集合的方法使用都差不多,也比较简单,所以博主这里就不啰嗦了(绝对不是因为懒得展示,哈哈)。

从图中我们可以看到,List下面有一些实现类,比如:ArrayList集合 和 LinkedList集合。

ArrayList集合:

ArrayList集合的特点:底层是也是数组实现,特点是:查询快增删慢。

因为其底层是数组的原因,所以该集合也满足数组的特征,数组下面有类似于索引的下标,所以查询起来比较快,但是由于数据是依次储存,在进行增删时,需要将其他数据依次前移或者后移补齐,所以效率较慢。

LinkedList集合:

LinkedList集合的特点:底层是链表实现,特点是:查询慢增删快。

和ArrayList不同,LinkedList底层是链表来实现的。链表在存储数据时,是通过指向下一个元素,就像铁链一样,一环扣一环地存储的。在需要增加数据时,只需要把指向重新指给添加的元素,在删除数据时,也只需要取出该数据的这一环,再将前后的数据指向连接起来即可。

但是,在查询元素时,没查询一次,都需要从第一个元素开始查询,这就导致了,数据查询的效率很慢。

综上,我们在存储数据时,对于集合的选择,应该以实际的需求再来做判断。

LinkedListd特有的方法:

 Set集合:

Set集合的特点:元素存取有序不包含重复的元素,没有带索引的方法,所以不能用普通for循环遍历,只能通过迭代器或者增强for循环遍历。

Set集合的底层是哈希表,所他的这些特性是通过哈希表来表现出来的。

哈希表,一个元素为链表的数组,综合了链表(存储速度快)和数组(查询速度快)的优点。

在存储元素时,元素会先通过hashCode()方法来获取哈希值,如果哈希值相同,就会判断内容是否相同,如果内容也一致,就表明元素是同一个元素,就不给予储存。这就保证了元素的唯一性。

在Set集合下面有HashSet集合TreeSet集合。

HashSet集合:

HashSet集合的特点: 底层数据结构是哈希表。

                                    没有带索引的方法,不能用普通for循环遍历。

                                    对集合的迭代顺序不作保证(无序)。

                                    不包含重复元素。

HashSet是Set集合,所以继承于Set集合的特征。

现在,我们来详细看看Set集合保证元素的唯一性的源码分析。

HashSet保证元素唯一性源码分析:

HashSet集合保证元素唯一性的原理

1.根据对象的哈希值计算存储位置:

               如果当前位置没有元素则直接存入;

               如果当前位置有元素存在,则进入第二步;

2.当前元素的元素和已经存在的元素比较哈希值

                如果哈希值不同,则将当前元素进行存储;

                如果哈希值相同,则进入第三步;

3.通过equals()方法比较两个元素的内容

               如果内容不相同,则将当前元素进行存储;

               如果内容相同,则不存储当前元素;

HashSet集合保证元素唯一性的图解:

 在HashSet下面,又有LinkedHashSet。

LinkedHashSet集合特点:

  • 哈希表和链表实现的Set接口,具有可预测的迭代次序

  • 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的

  • 由哈希表保证元素唯一,也就是说没有重复的元素

LinkedHashSet,在Set家族中最大的特点,就是可以保证元素的有序,所以,在需要实现元素的有序时,我们就多了一种选择。

TreeSet集合:

TreeSet集合特点:

        元素有序可以按照一定的规则进行排序,具体排序方式取决于构造方法:

                TreeSet():根据其元素的自然排序进行排序;

                TreeSet(Comparator comparator) :根据指定的比较器进行排序。

        没有带索引的方法,所以不能使用普通for循环遍历。

        由于是Set集合,所以不包含重复元素的集合。

TreeSet集合底层:使用的数据结构是二叉树;

TreeSet添加元素原则:左小右大;

Comparable和Comparator区别:

                     Comparable是直接在创建对象的类中实现
                     Comparator是建一个单独的比较器类来实现,或使用匿名内部类。将new出比较器的对象传进去【TreeSet list=new TreeSet<>(比较器对象)】

现在,我们来看看双列集合:Map

Map集合:

格式:interface Map<K,V>  K:键的类型;V:值的类型

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

特点:

        键值对映射关系;

        一个键对应一个值;

        键不能重复,值可以重复;

        元素存取无序;

Map集合的基本方法:

 Map集合的获取功能:

HashMap集合:

底层是哈希表数据结构,线程是不同步的,可以存入null键,null值。要保证键的唯一性,需要覆盖hashCode方法,和equals方法。

Map集合的遍历方式:

代码举例:

public class Test02 {
    public static void main(String[] args) {
        Map<Student, String> m = new HashMap<>();

        Student s1 = new Student("xishi", 23);
        Student s2 = new Student("wagnzhaojun", 24);
        Student s3 = new Student("yangyuhuan", 25);
        Student s4 = new Student("diaochan", 26);
        Student s5 = new Student("diaochan", 26);

        m.put(s1,"杭州");
        m.put(s2,"长安");
        m.put(s3,"长安");
        m.put(s4,"洛阳");
        m.put(s5,"洛阳");

根据键找值:

 Set<Student> s=m.keySet();//获取所有键的集合
        for (Student ss :s){
            String value = m.get(ss);//通过键来获取集合里的值
            System.out.println(ss+" 地址:"+value);
        }

根据键值对对象来找键和值:

Set<Map.Entry<Student, String>> map=m.entrySet();//获取键值对
        for (Map.Entry<Student, String> map1 : map){
            Student key=map1.getKey();//通过键值对获取键
            String value=map1.getValue();//通过键值对获取值
            System.out.println(key+" 地址:"+value);
        }

Map集合的综合使用--斗地主案列:

public class Chess {
    public static void main(String[] args) {
        Map<Integer, String> m = new HashMap<>();

        ArrayList<Integer> array = new ArrayList<>();
        String[] Color = {"♠", "♥", "♣", "♦"};
        String[] number = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"};

        int index = 0;
        for (String s1 : Color) {
            for (String s2 : number) {
                m.put(index, s1 + s2);
                array.add(index);
                index++;
            }
        }
        m.put(index, "小王");
        array.add(index);
        index++;
        m.put(index, "大王");
        array.add(index);

        Collections.shuffle(array);//洗牌,将序号随机出来

        TreeSet<Integer> dc = new TreeSet<>();
        TreeSet<Integer> wzj = new TreeSet<>();
        TreeSet<Integer> yyh = new TreeSet<>();
        TreeSet<Integer> dpSet = new TreeSet<>();

        for (int i = 0; i < array.size(); i++) {
            int x = array.get(i);//把打乱的序号赋值给x
            if (i >= array.size() - 3) {//如发到了底牌,存到dpSet中;
                dpSet.add(x);
            } else if (i % 3 == 0) {//对3取余,依次给三人发牌
                dc.add(x);
            } else if (i % 3 == 1) {//对3取余,依次给三人发牌
                wzj.add(x);
            } else if (i % 3 == 2) {//对3取余,依次给三人发牌
                yyh.add(x);
            }
        }
        lookpoker("貂蝉",dc,m);
        lookpoker("王昭君",wzj,m);
        lookpoker("杨玉环",yyh,m);
        lookpoker("底牌",dpSet,m);

    }
    //定义看牌方法
    public static void lookpoker(String name,TreeSet<Integer> t,Map<Integer, String> m){
        System.out.print(name+" 的牌是:");
        for (Integer key : t){
            String poker=m.get(key);
            System.out.print(poker+",");
        }

        System.out.println();
    }
}

并发修改异常:

出现原因:    迭代器遍历的过程中,通过集合对象修改了集合中的元素,造成了迭代器获取元素中判断预期修改值和实际修改值不一致,则会出现:ConcurrentModificationException

解决的方案:用for循环遍历,然后用集合对象做对应的操作即可。

列表迭代器:

ListIterator介绍:

        通过List集合的listIterator()方法得到,所以说它是List集合特有的迭代器
        用于允许程序员沿任一方向遍历的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置。

注意:

        在使用 E previous 返回列表中的上一个元素时, 如果想要将集合里的数据反转, 得先将迭代器的指向 到最后一位元素,这样才能从最后向前面执行。

Java面试中几个集合面试题

ArrayList和LinkedList有何区别?

ArrayList和LinkedList两者都实现了List接口,但是它们之间有些不同。
(1)ArrayList是由Array所支持的基于一个索引的数据结构,所以它提供对元素的随机访问,复杂度为O(1),但LinkedList存储一系列的节点数据,每个节点都与前一个和下一个节点相连接。所以,尽管有使用索引获取元素的方法,内部实现是从起始点开始遍历,遍历到索引的节点然后返回元素,时间复杂度为O(n),比ArrayList要慢。
(2)与ArrayList相比,在LinkedList中插入、添加和删除一个元素会更快,因为在一个元素被插入到中间的时候,不会涉及改变数组的大小,或更新索引。
(3)LinkedList比ArrayList消耗更多的内存,因为LinkedList中的每个节点存储了前后节点的引用。

Set和List的区别

  1. Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。都可以存储null值,但是set不能重复所以最多只能有一个空元素。
  2. Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>。
  3. List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 <实现类有ArrayList,LinkedList,Vector> 。

HaspMap与TreeMap的区别:

  1. HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。
  2. 在Map 中插入、删除和定位元素,HashMap是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode()和 equals()的实现。

Collection和Collections的区别

Collection是单列集合的顶层接口,Map是双列集合的顶层接口

Collections是一个集合的工具类,提供了排序、查找等操作集合的一些常用方法。

感谢各位英雄耐心地看到这里,希望博主的文章对英雄有那么一内内的用~~,点个赞呀~

 

评论 45
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值