容器集合(集合的进阶,Collection,List,Set,Map,Map集合的综合使用--斗地主案列,并发修改异常,列表迭代器,Java面试中几个集合面试题)
Posted ck_67
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了容器集合(集合的进阶,Collection,List,Set,Map,Map集合的综合使用--斗地主案列,并发修改异常,列表迭代器,Java面试中几个集合面试题)相关的知识,希望对你有一定的参考价值。
目录
集合的体系结构
我们先来了解下,集合类的特点:
提供一种存储空间可变的存储模型,存储的数据容量可以随时发生改变。
集合类的体系图:
通过图,我们可以看到:
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的区别
- Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。都可以存储null值,但是set不能重复所以最多只能有一个空元素。
- Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>。
- List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 <实现类有ArrayList,LinkedList,Vector> 。
HaspMap与TreeMap的区别:
- HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。
- 在Map 中插入、删除和定位元素,HashMap是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode()和 equals()的实现。
Collection和Collections的区别
Collection是单列集合的顶层接口,Map是双列集合的顶层接口
Collections是一个集合的工具类,提供了排序、查找等操作集合的一些常用方法。
感谢各位英雄耐心地看到这里,希望博主的文章对英雄有那么一内内的用~~,点个赞呀~
以上是关于容器集合(集合的进阶,Collection,List,Set,Map,Map集合的综合使用--斗地主案列,并发修改异常,列表迭代器,Java面试中几个集合面试题)的主要内容,如果未能解决你的问题,请参考以下文章
容器集合(集合的进阶,Collection,List,Set,Map,Map集合的综合使用--斗地主案列,并发修改异常,列表迭代器,Java面试中几个集合面试题)