集合基础

集合类

重点:

常见的集合类(List集合、Set集合、Map集合)

各种集合的特点,重点掌握集合的遍历、添加对象、删除对象的方法

要求:

会使用集合类

集合类是干什么的?

​ 集合类是一种容器,类似于数组,但又与数组不同。

不同体现在:

数组的长度是固定的,集合类的长度是可变的。

数组中主要存放的是基本类型的数据,也可以存放对象引用;集合类只能存放的是对象引用(如果使用基本数据类型,那么需要使用对应的包装类)。

数组中的数据类型必须是相同的,集合不需要一定相同。​

注意:集合类由接口实现,接口所在的包是java.util

集合的分类?

​ 集合可以分为List集合、Map集合、Set集合。

为什么又这么多不同类型的集合?

​ 集合可以存储多个元素,但是我们对于元素的需求不一定相同,所以出现了很多类型的集合。有如下几种不同的需求,

多个元素,元素不可以相同(Set集合中不允许有相同的元素)

多个元素,元素按照一定的顺序排列(Set集合和Map集合的实现类TreeXxx排列是有顺序的)

多个元素,增加、删除速度需求(Set集合和Map集合的实现类HashXxx的增加、删除速度快,根本的原因在于底层数据结构不同)

集合类的继承关系?

​ Collection接口是继承结构中的顶级接口;

​ Collection接口是Set接口、List接口、Queue接口的父接口,我们常用到的是Set接口和List接口;

​ Map接口不继承Collection接口;


Collection接口

什么是Collection接口?

​ Collection接口是层次结构中的根接口。

有关Collection接口的概念?

元素:构成Collection的单位称为元素。

Collection接口的特点?

​ Collection接口是不可以直接使用的,但是Collection接口提供了以下几种功能:

添加功能(add(Object o)、addAll(Collection c))

删除功能(remove(Object o)、removeAll(Collection c)、clear())

判断功能(contains(Object o)、containsAll(Collection c)、isEmpty())

获取功能(iterator())

长度功能(size())

交集功能(retainAll(Collection c))

因为List接口和Set接口都是继承了Collection接口,所以可以使用Collection接口的功能。具体的方法如下:

方法返回值功能描述

add(Object o)boolean添加一个元素到指定的集合中

addAll(Collection c)boolean添加一个集合的元素到指定的集合中

remove(Object o)boolean将指定的元素从指定集合中移除

removeAll(Collection c)boolean移除一个集合中的元素,只要一个元素被移除了,那么返回true,相当于clear()

clear()void移除集合中所有元素

contains(Object o)boolean判断集合是否包含该元素,满足条件返回true,否则返回false

containsAll(Collection c)boolean判断集合中是否包含指定集合中的所有元素,满足条件返回true,否则返回false

isEmpty()boolean判断当前集合是否为空,为空返回true,否则返回false

iterator()Iterator<E>返回在此Collection的元素上进行迭代的迭代器,用于遍历集合中的对象

方法返回值功能描述

size()int获取该集合中元素的个数,返回int型值

retainAll(Collection c)boolean求两个集合的交集,返回值表示调用方法的集合是否发生变化,如果发生变化返回true,否则返回false

为什么Collection中有Iterator()方法?

​ 因为Collection继承了Iterator。

为什么遍历集合时候需要使用iterator()方法,创建集合迭代器

​ 回答:类似于数组,数组需要下标索引才能遍历,创建集合迭代器的作用就是获得集合的索引,用于集合的遍历。

什么是迭代器,有什么作用?

迭代器(Iterator)模式,又叫做游标模式,它的含义是,提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节,用于集合遍历。

hasNext()、next()方法如何使用?

方法返回值功能描述

hasNext()boolean判断是否有元素迭代, 如果仍有元素可以迭代,则返回 true,否则返回false

next()返回迭代的下一个元素

迭代器中的方法是如何实现的呢?

​ 迭代器是在ArrayList以内部类的方式实现的!并且,从源码可知:Iterator实际上就是在遍历集合

​ 我们遍历集合(Collection)的元素都可以使用Iterator,至于它的具体实现是以内部类的方式实现的!

实例化集合类对象的语法规则?

基本语法:集合接口<E> 对象引用名 = new 接口实现类<>()

代码实现

packagecn.wells;

importjava.util.*;

publicclassMuster{

publicstaticvoidmain(String[]args) {

Collection<String>list=newArrayList<>();        //实例化集合类对象

//用于向上转型

//ArrayList类是Collection的子接口List的实现类

list.add("a");//向集合类中添加数据

list.add("b");

list.add("c");

Iterator<String>it=list.iterator();//创建迭代器,用于遍历集合

while(it.hasNext()) {//判断是否有下一个元素

Stringstr=(String)it.next();//获取集合中的元素

System.out.println(str);

       }

   }

}

List集合

List集合包括什么?

​ List集合包括List接口以及List接口所有实现类。

List集合的特点?

​ List集合中的元素允许重复各元素的顺序就是对象插入的顺序(有顺序)。这样的特点类似于数组,可以通过索引来访问集合中的元素。

List接口

​ 因为List接口继承了Collection接口,所以继承了Collection中的所有的方法。其中有两个独有的,比较重要的方法:

方法功能描述

get(int index)获取指定索引位置的元素

set(int index, Object o)将集合中指定索引位置的对象修改为指定的对象

Collection返回的是Iterator迭代器接口,那么List中有什么自己对应的实现吗?

​ ListIterator接口

Iterator迭代器接口和ListLterator接口有什么不一样吗?

​ ListIterator接口比Iterator接口的几个方法,主要的功能是遍历、添加元素和设置元素

List接口实现类

​ List接口常用实现类有ArrayList类与LinkedList类

List集合的继承关系


注意:ArrayList因为有扩容这个概念,所以可以实现动态增长

ArrayList类的缺点和优点?

优点:

ArrayList类实现了可变数组,允许保存所有的元素,包括null。根据索引位置对集合进行快速的随机访问。因为ArrayList的底层是数组。

缺点:

向指定的索引位置插入对象或删除对象速度较慢。

LinkedList类的优点和缺点?

优点:

LinkedList类采用链表结构保存对象。优点是便于向集合中插入和删除对象,并且效率较高。因为LinkedList底层是链表。

缺点:

随机访问LinkedList类中对象效率较低。

补充:List实现的子类还有Vector类

List实现的子类的线程安全是怎么样的?

​ ArrayList类和LinkedList类是不安全的,而Vector类是安全的。

ArrayList类和LinkedList类实例化对象的语法是什么?

类语法

ArrayListList<E> list = new ArrayList<>()

LinkedListList<E> list = new ArrayList<>()

注意:

语法格式中的E表示Java中合法的数据类型。例如,集合中的元素是字符串类型,那么这里的E就可以修改为String。

与数组相同,集合的索引也是从0开始的

代码实现

packagecn.wells;

importjava.util.*;

publicclassGather{

publicstaticvoidmain(String[]args) {

List<String>list=newArrayList<>();//创建集合对象


list.add("a"); //向集合添加元素

list.add("b");

list.add("c");

inti=(int)(Math.random()*list.size());            //获取索引范围内的随机数

System.out.println("随机获取数组中的元素:"+list.get(i));                                              //获取指定索引的元素

list.remove(2);//使用的是Collection接口中的方法      //将指定索引位置的元素从集合中移除

System.out.println("将索引'2'的元素从数组中移除后,数组中的元素是:");

//遍历集合

for(intj=0;j<list.size();j++) {

System.out.println(list.get(j));

       }  

   }

}

Set集合

Set集合的特点?

Set集合中不能包含重复对象

Set集合中的对象不按特定的方式排列(无顺序),只是简单地把对象加入集合中。

Set集合的组成?

​ Set集合由Set接口和实现类组成。

​ 和List接口一样,Set接口继承了Collection接口,所以包含Collection接口中的所有方法。

​ Set集合实际上就是HashMap进行构造的

Set集合必须注意的问题

​ Set的构造有一个约束条件,传入的Collection对象不能有重复值,必须小心操作可变对象(Mutable Object)。如果Set中的可变元素改变了自身状态导致Object.equals(Object) = true,则会出现某些问题。因为已经不满足Set中不能包含重复对象的基本条件。

Set接口实现类

​ Set接口常见的实现类是HashSet类和TreeSet类

HashSet类的优缺点?

​ Hash类由哈希表支持,实际上是一个HashMap实例。

优点:

允许使用null值,因为底层数据结构是哈希表(元素为链表的数组)

缺点:

不保证Set的迭代顺序,特别是它不保证该顺序恒久不变(无顺序)

TreeSet类的优点?

​ 在遍历集合时不仅可以按照自然顺序递增排序,还可以按照指定比较器递增排序,也就是可以通过比较器对用TreeSet类实现的Set集合中的对象进行排序(原因:TreeSet类不仅实现了Set接口,还实现了java.util.SortedSet接口)。

​ TreeSet类底层结构是红黑树(一个自平衡的二叉树),以此来保证元素的排列方式。

补充:Set集合实现的子类还有LinkedHashSet类,底层由哈希表和链表组成

什么时比较器?

​ 一个对象中有多个属性,选择器就是选择什么属性进行排序。比较器主要用于对对象的排序。

TreeSet类中独特的方法

方法功能描述

first()返回Set中当前第一个(最低)元素

last()返回Set中当前最后一个(最高)元素

comparator()返回对此Set中的元素进行排序的比较器。如果此Set使用自然排序,则返回null

headSet(E toElement)返回一个新的Set集合,新集合是toElement(不包含)之前的所有对象

subSet(E fromElement, E fromElment)返回一个新的Set集合,是fromElement(包含)对象与fromElement(不包含)之间的所有对象

tailSet(E fromElement)返回一个新的Set集合,新集合包含对象fromElement(包含)之后的所有对象

代码实现

packagecn.wells;

importjava.util.Iterator;

importjava.util.TreeSet;

publicclassUpdateStuimplementsComparable<Object>{

Stringname;

longid;


publicUpdateStu(Stringname,longid) {

this.name=name;

this.id=id;

   }

    //重写Comparable接口中的compareTo()方法,比较该对象和指定对象的顺序,如果该对象小于、等于、大于指定对象,则返回负整数、0或正整数。

//哪里用到了这个方法,为什么这个方法会影响后面的headSet()方法和subSet()方法

publicintcompareTo(Objecto) {

UpdateStuupstu=(UpdateStu)o;

intresult=id>upstu.id?1: (id==upstu.id?0:-1);

returnresult;

   }

publicStringgetName() {

returnname;

   }

publicvoidsetName(Stringname) {

this.name=name;

   }

publiclonggetId() {

returnid;

   }

publicvoidsetId(longid) {

this.id=id;

   }

publicstaticvoidmain(String[]args) {

UpdateStustu1=newUpdateStu("李同学",01011);  //创建UpdateStu对象

UpdateStustu2=newUpdateStu("陈同学",01021);

UpdateStustu3=newUpdateStu("王同学",01051);

UpdateStustu4=newUpdateStu("马同学",01012);

TreeSet<UpdateStu>tree=newTreeSet<>();        //创建TreeSet对象

tree.add(stu1);//向集合中添加对象

tree.add(stu2);

tree.add(stu3);

tree.add(stu4);

Iterator<UpdateStu>it=tree.iterator();        //Set集合中所有对象的迭代器

System.out.println("Set集合中的所有元素:");

while(it.hasNext()) {

UpdateStustu=(UpdateStu)it.next();

System.out.println(stu.getId()+" "+stu.getName());

       }

//会有"java.lang.IllegalArgumentException: fromKey > toKey"异常

it=tree.headSet(stu2).iterator();                //截取排在stu2对象之前的对象

System.out.println("截取前面部分的集合:");

while(it.hasNext()) {

UpdateStustu=(UpdateStu)it.next();

System.out.println(stu.getId()+" "+stu.getName());

       }

//会有"java.lang.IllegalArgumentException: fromKey > toKey"异常

it=tree.subSet(stu2,stu3).iterator();            //截取排在stu2对象与stu3对象之间的对象

System.out.println("截取前面部分的集合:");

while(it.hasNext()) {

UpdateStustu=(UpdateStu)it.next();

System.out.println(stu.getId()+" "+stu.getName());

       }

   }

}

问题:headSet()方法和subSet()方法与compareTo()方法有什么联系,为什么返回的值会对headSet()方法和subSet()方法有影响?为什么要重写Comparable接口中的compareTo()方法?

注意:headSet()、subSet()、tailSet()方法截取对象生成新集合时是否包含指定的参数,可通过如下方法进行判断:如果指定参数位于新集合的起始位置,则包含该对象,如subSet()方法的第一个参数和tailSet()方法的参数;如果指定参数是新集合的最终位置,则不包含该参数,如headSet()方法的入口参数和subSet()方法的第二个入口参数。

理解:TreeSet类中的headSet()、subSet()、tailSet()等方法都是用于截取指定集合中的对象,但是有时候可以截取到对象,有的时候不可以。如果从指定参数位置往前截取,那么不包含这个参数所指定的对象。如果从指定参数往后截取,包含这个参数所指定的对象。


Map集合

Map集合的继承关系


Map集合的特点?

Map集合没有继承Collection接口,将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射一个值

Map集合的组成?

Map集合包含Map接口以及Map接口的所有实现类

我们为什么需要Map集合来存储数据结构呢?

​ 举一个例子,作为学生,我们是根据学好进行区分。只要我们直到学号,那么我们就可以获取学生信息。这就是Map映射的作用。

Map和Collection有什么区别?

​ Map集合存储元素是成对出现的,Map的键是唯一的,键是可以重复的。

​ Collection集合存储元素是单独出现的,Collection的子类Set是唯一的,List是课重复的。

​ 其中要注意,Map集合的数据结构针对键有效,与值无关。Collection集合的数据结构针对元素有效。

Map集合中的key和value的特点?

Map中不能包含相同的key,每个key只能映射一个value

key决定了存储对象在映射中的存储位置,不是由key本身决定的,而是由一种"散列技术"进行处理,产生一个散列码的整数值。

​ 无论是Set还是Map,我们可以发现都会有对应的HashMap、HashMap,那么就涉及到了链表的知识。以下是链表的优缺点,

​ (1)链表和数组都可以按照人们的意愿来排列元素的次序,它们可以说是有序的(存储的顺序和去除的顺序是一致的)

​ (2)也会带来缺点:如果想要获取某个元素,就需要访问所有的元素,直到找到为止,所以会消耗很多的时间。

散列码是什么?

为了能够快速查找元素的数据,就出现了散列码这种数据。

散列码常用作一个偏移量,该偏移量对应分配给映射的内存区域的起始位置,从而确定存储对象在映射中的存储位置。

散列码的工作原理?

​ 散列码为每个对象计算出一个整数,称为散列码。根据这些计算出来的整数(散列码)保存在对应的位置上。

Map接口

​ Map接口提供了将key映射到值的对象。一个映射不能包含重复的key,mzgekey最多映射到一个值。

Map接口的功能

1、添加功能(put(K key, V value))

2、删除功能(clear()、remove(Object key))

3、判断功能(containsKey(Object key)、containsValue(Object value)、isEmpty())

4、获取功能(Set<Map.Entry<K key, V value>entrySet()

5、长度功能

方法返回值功能描述

put(K key, V value)V向集合中添加指定的key与value的映射关系 ,如果键是第一次存储,就直接存储元素,返回null;如果不是第一次存储,那么把原来的值替换掉,返回以前的值

clear()void移除所有的键值对元素

remove(Object k)V根据键删除值,然后把值返回

containsKey(Object key)boolean判断集合中是否包含指定的键

containsValue(Object value)boolean判断集合中是否包含指定的值

isEmpty()boolean判断集合是否为空

entrySet()Set<Map.Entry<K eky, V value>返回的是键值对对象的集合

get(Object key)V如果存在指定的key对象,则返回该对象对应的值,否则返回null

keySet()Set<K>获取集合中的所有键的集合

方法返回值功能描述

values()Collection<V>获取集合中所有值的集合

size()int返回集合中键值对的对数

代码实现

packagecn.wells;

importjava.util.*;

publicclassUpdateStu2{

publicstaticvoidmain(String[]args) {

Map<String,String>map=newHashMap<>();        //创建Map实例

map.put("01","李同学");//向集合中添加对象

map.put("02","魏同学");

Set<String>set=map.keySet();                    //构造Map集合中的所有key对象的集合

Iterator<String>it=set.iterator();            //创建集合迭代器

System.out.println("key集合中的元素:");

while(it.hasNext()) {//遍历集合

System.out.println(it.next());

       }

Collection<String>coll=map.values();

it=coll.iterator();

System.out.println("value集合中的元素:");

while(it.hasNext()) {//遍历集合

System.out.println(it.next());

       }  

   }

}

注意:Map集合中允许值对象是null,而且没有个数限制,例如,可通过map.put("05", null)语句向集合中添加对象。

Map接口的实现类

Map接口的实现类有哪些?

​ Map接口实现的类有HashMap类和TreeMap类

为什么推荐使用HashMap类实现Map集合?

​ HashMap类实现的Map集合添加和删除映射关系效率更高(原因:HashMap是基于哈希表的Map接口的实现,HashMap通过哈希表对其内部的映射关系进行快速查找)

什么情况下使用TreeMap类实现Map集合?

希望Map集合中的对象存在一种顺序(原因:TreeMap的映射关系存在一定的顺序)

HashMap类的特点?

HashMap基于哈希表的Map接口实现,提供了可选的映射操作。在保证键的唯一性下,允许使用null值和null键。

HashMap通过哈希表对其内部的映射关系进行快速查找

HashMap不保证映射的顺序,特别是它不保证该顺序恒久不变

TreeMap类的特点?

TreeMap类不仅实现了Map接口,还实现了java.util.sortedMap接口,因此,集合中的映射关系具有一定的顺序

在添加、删除或定位映射关系时,TreeMap类比HashMap类差

由于TreeMap类实现的Map集合钟的映射关系是根据对象按照一定顺序排列的,因此键对象不会是null

代码实现

packagecn.wells;

publicclassEmp{

privateStringe_id;

privateStringe_name;


publicEmp(Stringe_id,Stringe_name) {

this.e_id=e_id;

this.e_name=e_name;

   }

publicStringgetE_Id() {

returne_id;

   }

publicvoidsetE_Id(Stringe_id) {

this.e_id=e_id;

   }

publicStringgetE_Name() {

returne_name;

   }

publicvoidsetE_Name(Stringe_name) {

this.e_name=e_name;

   }

}

packagecn.wells;

importjava.util.*;

publicclassMapTest{

publicstaticvoidmain(String[]args) {

Map<String,String>map=newHashMap<>();        //由HashMap实现Map对象

Empemp=newEmp("351","张三");                  //创建Emp对象

Empemp2=newEmp("512","李四");

Empemp3=newEmp("853","王一");

Empemp4=newEmp("125","赵六");

Empemp5=newEmp("341","黄七");


map.put(emp.getE_Id(),emp.getE_Name());      //将对象添加到集合中

map.put(emp2.getE_Id(),emp2.getE_Name());

map.put(emp3.getE_Id(),emp3.getE_Name());

map.put(emp4.getE_Id(),emp4.getE_Name());

map.put(emp5.getE_Id(),emp5.getE_Name());

Set<String>set=map.keySet();                    //获取Map集合中的key对象集合

Iterator<String>it=set.iterator();

System.out.println("HashMap类实现的Map集合,无序:");

while(it.hasNext()) {

Stringstr=(String)it.next();                    //获取集合中的key对象

Stringname=(String)map.get(str);                //获取集合中的values对象

System.out.println(str+" "+name);


       }

TreeMap<String,String>treemap=newTreeMap<>();

treemap.putAll(map);

Iterator<String>iter=treemap.keySet().iterator();

System.out.println("TreeMap类实现的Map集合,键对象升序:");

while(iter.hasNext()) {

Stringstr=(String)iter.next();              //获取集合中的key对象

Stringname=(String)treemap.get(str);            //获取集合中的values对象

System.out.println(str+" "+name);


       }  

   }    

}

发现:如果是TreeXxx类,那么就是有顺序的,如果是HashXxx类,就是没有顺序的,但是添加元素、删除元素会更加方便。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352