Java编程基础倒数第二篇,感谢没有放弃的自己。 学习笔记参考书籍《Java编程基础》主编 张焕生。本书内容比较适合没有什么基础的入门小白,学完一章还有习题,比较适合初学者。 自律、积极、勤奋以及先从一个怎么样都不可能不会实现的小目标开始。
本文已收录于[ 专栏 ]
《Java入门》系列
前面[ 章节 ]:
Java必备基础十六——三万字总结输入与输出流
Java必备基础十五——万字长文总结异常处理基本知识点
Java必备基础十四——内部类详细知识点归纳
Java必备基础十三——接口详细知识点归纳
Java必备基础十二——抽象类
✨Java必备基础十一——多态详解以及多态原则
Java必备基础十——类的继承详解
Java必备基础九——包装类
Java必备基础八——Math类、Random类、日期时间类
Java必备基础七——字符串的基本常用方法
Java必备基础六——一维数组
Java必备基础五——类的封装
Java必备基础四——成员变量和局部变量
Java必备基础三——方法的声明与调用,递归
Java必备基础二——类和对象
Java必备基础一——Java语言基础
一、Java集合介绍
1.1 什么是集合?
Java是面向对象的语言,我们在编程的时候自然需要存储对象的容器,数组可以满足这个需求,但是数组初始化时长度是固定的,但是我们往往需要一个长度可变化的容器,因此,集合出现了。
Java集合在java.util包中,这些集合可以看作是容器,用来存储、获取、操纵和传输具有相同性质的多个素。
现实中的容器主要是添加对象、删除对象、清空对象等。衣柜里面的衣服,可以放入和取出,也可以有序摆放,以便快速的查找,Java集合也是如此,有些是方便插入和删除的,有些是为了方便查找数据。
1.2 集合类的继承关系
Collection接口是集合类的根接口,Java中没有提供这个接口的直接的实现类。 Map是Java.util包中的另一个接口,它和Collection接口没有关系,是相互独立的,但是都属于集合类的一部分。==Map包含了key-value对。Map不能包含重复的key,但是可以包含相同的value==。
Java中常用的集合类有List集合、Set集合和Map集合。其中List集合和Set集合继承了Collection接口(Java5后新增了队列Queue),List接口的实现类为ArrayList,LinkedList;
Map接口有两个实现类,HashMap,HashTable,如下图:
1.3 集合和数组的区别
- 长度区别:数组是静态的,一个数组实例长度不可变,一旦创建了就无法改变容量;集合是可以动态扩展容量,集合长度可变,可以根据需要动态改变大小,集合提供更多的成员方法,能满足更多的需求;在编写程序时不知道对象个数时,在空间不足的情况下要做到自动扩增容量,优先使用集合来实现,数组此时不适用
- 内容区别:集合不声明可存储素类型,集合可存储不同类型素;数组声明了它容纳的素的类型且只可存放单一类型素
- 素区别:集合只能存储引用类型素,数组可存储引用类型,也可存储基本类型
- 数组是java语言中内置的数据类型,是线性排列的,执行效率或者类型检查都是最快的。
下面就详细介绍各个集合类。
二、Collection接口和Iterator接口
2.1 Collection接口
上面说过,Collection接口是List接口、Set接口和的父接口,该接口中定义的方法可用于Set和List集合。Collection接口中定义了一些操作集合的方法。
2.1.1 Collection接口的常用方法
方法 |
说明 |
boolean add(Object o) |
向集合中加入指定对象o,增加成功返回true,失败false |
boolean addAll(Collection c) |
将指定集合c内的所有素添加到该集合内,增加成功返回true,否则返回false |
void clear() |
删除集合内的所有素 |
boolean contains(Object o) |
判定集合内是否包含指定素,是返回true |
boolean containsAll(Collection c) |
判定集合内是否包含集合c的所有素 ,是返回true |
boolean isEmpty() |
判定是否为空集合,是返回true |
Iterator iterator() |
返回一个Iterator对象,可以用来遍历集合中的素 |
boolean remove(Object o) |
从集合中删除指定素 o,成功则返回true |
boolean removeAll(Collection c) |
删除该集合中包含集合c的所有素,若删除了1个及以上的素则返回true |
boolean retainAll(Collection c) |
删除该集合中除集合c中素以外的素,若调用该方法的集合素改变了,则返回true |
int size() |
返回集合中素的数目 |
Object[] toArray() |
返回一个数组,该数组中包括集合中的所有素 |
2.1.2 Collection常用方法操作集合举例
public class Example8_1 { public static void main(String[] args) { Collection collection = new ArrayList();//将子类对象赋值给一个父类的引用变量 collection.add("1"); collection.add("2");//向集合中添加素 System.out.println("collection集合的素个数为:"+collection.size()); collection.clear();//删除所有素 System.out.println("collection集合是否没有任何素:"+collection.isEmpty()); collection.add("3"); collection.add("4"); System.out.println("collection集合中是否包含\"4\"字符串:"+collection.contains("4")); Collection collection1 =new ArrayList(); collection1.add("3"); collection1.add("4"); collection1.add("c"); collection1.retainAll(collection);//从collection1删除collection中不包含的素 System.out.println("collection1集合的素:"+collection1); System.out.println("collection集合是否完全包含collection1集合:"+collection.containsAll(collection1)); System.out.println("collection集合的素:"+collection); } } 复制代码
编译和运行后的结果为:
collection集合的素个数为:2 collection集合是否没有任何素:true collection集合中是否包含"4"字符串:true collection1集合的素:[3, 4] collection集合是否完全包含collection1集合:true collection集合的素:[3, 4] 复制代码
2.2 Iterator接口
2.2.1 Iterator接口作用?
如果要遍历集合中的素,在学数组时我们常用for循环遍历数组中的素,在集合中也可使用传统循环方法实现,此外,集合中也可以使用到Iterator对象来遍历集合的数组,此方法更简单。
Iterator通过遍历(迭代访问)集合中的素来获取或删除某素,仅用于遍历集合,可以应用于Set、List、Map以及其子类,Iterator对象也被称为迭代器。
ListIterator在Iterator基础商进行了扩展,允许双向遍历列表,而Iterator只能向后迭代,但ListIterator只能用于List及其子类。
2.2.2 Iterator接口的常用方法
方法 |
接口类型 |
说明 |
boolean hasNext() |
Iterator |
还有素可以迭代返回true |
Object next() |
Iterator |
返回下一个素 |
void remove() |
Iterator |
删除当前素 |
void add(Object o) |
ListIterator |
将指定素o插入集合,该素在下一次调用next()方法时被返回 |
boolean hasNext() |
ListIterator |
存在下一个素时返回true |
boolean hasPrevious() |
ListIterator |
存在前一个素时返回true |
Object next() |
ListIterator |
返回列表中的下一个素 |
Object previous() |
ListIterator |
返回列表中的前一个素 |
int nextIndex() |
ListIterator |
返回列表下一个素的下标,如果不存在下一个素,则返回列表的大小 |
int previousIndex() |
ListIterator |
返回列表前一个素的下标,如果不存在前一个素,则返回 -1 |
void remove() |
ListIterator |
删除当前素 |
void set(Object o) |
ListIterator |
将o赋值给当前素,即上一次调用next方法或previous方法后返回的素 |
2.2.3 Iterator常用方法举例
1.利用Iterator进行集合素的输出
class Example8_2 { public static void main(String[] args) { ArrayList arrayList = new ArrayList(); arrayList.add("a"); arrayList.add("b"); arrayList.add("c"); System.out.println("集合的内容为:"); Iterator iterator = arrayList.iterator();//iterator()方法返回一个Iterator对象 while (iterator.hasNext()){ Object o = iterator.next();//循环输出 System.out.println(o); if(o.equals("b")){ iterator.remove();//将当前素删除 } } System.out.println("删除b素后,集合的内容为:"+arrayList); } } 复制代码
编译和运行后的结果为:
集合的内容为: a b c 删除b素后,集合的内容为:[a, c] 复制代码
2.利用Iterator进行反向输出
class Example8_3 { public static void main(String[] args) { ArrayList arrayList = new ArrayList(); arrayList.add("a"); arrayList.add("b"); arrayList.add("c"); ListIterator listIterator = arrayList.listIterator();//返回ListIterator对象 while (listIterator.hasNext()){ System.out.println(listIterator.next()); } //将列表反向输出 while (listIterator.hasPrevious()){ Object o= listIterator.previous(); System.out.println(o); } } } 复制代码
编译和运行后的结果为:
a b c c b a 复制代码
此外,利用foreach循环迭代访问集合中的素也可以达到相同的效果:
for(Object obj : arrayList){ System.out.println(obj); } 复制代码
编译和运行后的结果为:
a b c 复制代码
三、List集合
List集合中素保持一定的顺序,并且允许素重复。List集合主要有两种实现类:ArrayList类和LinkedList类。
3.1 List接口
List接口实现了Collection接口,因此List接口有Collection接口提供的所有方法,而且List接口还提供了一些其他的方法。
3.1.1 List接口的常用方法
方法 |
说明 |
boolean add(int index, Object element) |
index为对象element要加入的位置,其他对象的索引位置相对后移1位,索引位置从0开始 |
E remove(int index) |
移出列表中指定位置素 |
E set(int index, E element) |
用指定素替换列表中指定位置素 |
E get(int index) |
返回列表中指定位置素 |
int indexOf(Object o) |
返回列表中指定素位置的索引。存在多个时,返回第一个的索引位置,不存在返回-1 |
int lastIndexOf(Object o) |
返回列表中指定素位置的索引。存在多个时,返回最后一个的索引位置,不存在返回-1 |
ListIterator<> listIterator() |
返回此列表素的列表迭代器(按适当顺序) |
ListIterator<> listIterator(int index) |
返回此列表素的列表迭代器(按适当顺序),从列表的指定位置开始 |
List <> subList(int fromIndex, int toIndex) |
返回一个指定区域的List集合对象,指定区域从索引fromIndex(包括)到索引toIndex(不包括) |
从表中可以看出,List接口提供的适合于自身的常用方法均与索引有关,这是因为==List集合为列表类型,以线性方式存储对象,可以通过对象的索引操作对象。==
List接口的常用实现类有ArrayList和LinkedList,在使用List集合时,通常情况下声明为List类型,实例化时根据实际情况的需要,实例化为ArrayList或LinkedList,例如:
List<String> l = new ArrayList<String>();// 利用ArrayList类实例化List集合 List<String> l2 = new LinkedList<String>();// 利用LinkedList类实例化List集合 复制代码
3.1.2 List接口的常用方举例
1. List常用方法举例
class Example8_4{ public static void main(String[] args) { String a = "A", b = "B", c = "C", d = "D", e = "E"; List<String> list = new LinkedList<String>(); list.add(a); list.add(e); list.add(d); list.set(1, b);// 将索引位置为1的对象e修改为对象b list.add(2, c);// 将对象c添加到索引位置为2的位置 Iterator<String> it = list.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } } 复制代码
在控制台将输出如下信息:
A B C D 复制代码
3.2 ArrayList类
3.2.1 ArrayList类的构造方法
方法 |
说明 |
ArrayList() |
构造一个初始容量为10的空数组 |
ArrayList(Collection<? extends E> c) |
构造一个包含Collection的素的数组,这些素按照Collection迭代器返回他们的顺序排列的 |
ArrayList(int initialCapacity) |
构造一个具有指定初始容量的空数组 |
ArrayList采用动态对象数组实现,默认构造方法创建一个初始容量为10的空数组,之后的扩容算法为:原来数组的大小+原来数组的一半。建议创建ArrayList时给定一个初始容量。 |
3.2.2 ArrayList类的常用方法举例
1. 利用ArrayList实现了List接口,ArrayList可以使用List接口常用方法。
class Example8_5{ public static void main(String[] args) { ArrayList arrayList = new ArrayList(); arrayList.add("a"); arrayList.add("b"); arrayList.add("c"); System.out.println("arrayList的素为:"+arrayList); arrayList.set(0,"c");//将索引为0的位置对象a修改为对象c System.out.println("arrayList的素为"+arrayList); arrayList.add(1,"e");//将对象e添加到索引为1的位置 System.out.print("arrayList的素为:"); for (int i=0;i<arrayList.size();i++){ System.out.print(arrayList.get(i));//for循环迭代arrayList集合素 } System.out.println(""); System.out.println("arrayList指定素c位置的索引为"+arrayList.indexOf("c"));//返回列表中指定素c位置的索引 System.out.println("arrayList指定素c最后位置的索引为"+arrayList.lastIndexOf("c"));//返回列表中指定素c最后位置的索引 System.out.println("arrayList的指定区域为"+arrayList.subList(1,2));//返回列表中指返回一个指定区域的List集合对象[1,2) } } 复制代码
编译和运行后的结果为:
arrayList的素为:[a, b, c] arrayList的素为[c, b, c] arrayList的素为:cebc arrayList指定素c位置的索引为0 arrayList指定素c最后位置的索引为3 arrayList的指定区域为[e] 复制代码
2. 利用ArrayList实现了List接口,ArrayList可以使用List接口常用方法。
class Person{ private String name; private long id; public String getName() { return name; } public void setName(String name) { this.name = name; } public long getId() { return id; } public void setId(long id) { this.id = id; } } class Example8_6 { public static void main(String[] args) { List<Person> list = new ArrayList<Person>(); String[] names = {"李白","杜甫"}; long[] id ={20222,22222}; for (int i=0;i<names.length;i++){ Person person = new Person(); person.setName(names[i]); person.setId(id[i]); list.add(person); } for (int i=0;i<list.size();i++){ Person person = list.get(i); System.out.println(person.getName()+person.getId()); } } } 复制代码
编译和运行后的结果为:
李白20222 杜甫22222 复制代码
3.3 LinkedList类
3.3.1 LinkedList类的常用方法
方法 |
说明 |
void addFirst(E e) |
将指定素插入此列表的开头 |
void addLast(E e) |
将指定素插入此列表的结尾 |
E getFirst() |
返回列表开头的素 |
E getLast() |
返回列表结尾的素 |
E removeFirst() |
移除列表开头的素 |
E removeLast() |
移除列表结尾的素 |
3.3.2 LinkedList类的常用方法举例
1.使用上表中的方法编写程序
public class Example8_7 { public static void main(String[] args) { LinkedList linkedList = new LinkedList(); linkedList.add("a"); linkedList.add("b"); linkedList.add("c"); linkedList.add("d"); //获得并输入列表开头的对象 System.out.println("列表开头素为:"+linkedList.getFirst()+"列表结尾素为:"+linkedList.getLast()); linkedList.addFirst("rr");//向列表开头添加一个对象 System.out.println("列表中所有素:"+linkedList); linkedList.removeLast();//移除列表结尾素 System.out.println("列表结尾素为:"+linkedList.getLast());//获取并输出列表结尾的对象 } } 复制代码
编译和运行后的结果为:
列表开头素为:a列表结尾素为:d 列表中所有素:[rr, a, b, c, d] 列表结尾素为:c 复制代码
3.4 List与ArrayList、LinkedList的比较
首先我们知道,List是一个接口,ArrayList、LinkedList是实现该接口的类。
==纯属个人想法部分== 我在学习时对比了几个例子,看到了几行代码,于是产生了一些问题:
List list; //正确 list=null; List list=new List(); // 是错误的用法 ArrayList arrayList = new ArrayList(); List list = new ArrayList(); List<String> list = new ArrayList<String>(); 复制代码
首先List是一个接口, 因此,List接口不能被构造,也就是我们说的不能创建实例对象,所以List list=new List() 是错误的用法;List list写法正确,构造了一个List引用;
其次ArrayList是List接口的一个实现类,ArrayList有自己的构造方法,所以ArrayList arrayList = new ArrayList()是正确的写法,构造了一个ArrayList对象,此对象保留ArrayList的所有属性;
而List list = new ArrayList()这句创建了一个ArrayList的对象后向上转型为List。此时它是一个List对象了,有些ArrayList有但是List没有的属性和方法,它就不能再用了。(想到多态的一些解释:==接口和抽象类都不能被实例化,但是它们可以创建一个指向自己的对象引用,它们的实现类或子类就在充当这样的角色,这就是面向对象编程中多态的优势==)
前面学到多态性的原则:list拥有List的所有属性和方法,不会拥有其实现类ArrayList的独有的属性和方法。 如果List与ArrayList中有相同的属性(如int i),有相同的方法(如void f()), 则list.i是调用了List中的i , list.f()是调用了ArrayList中的f();
再进一步,List list = new ArrayList(),为什么要用 List list = new ArrayList() ,而不用 ArrayList alist = new ArrayList()呢? 问题就在于List接口有多个实现类,现在你用的是ArrayList,也许哪一天你需要换成其它的实现类,如 LinkedList或者Vector等等,这时你只要改变这一行就行了: list = new LinkedList(); ,这样的形式使得list这个对象可以有多种的存在形式,其它使用了list地方的代码根本不需要改动。假设开始用ArrayList alist = new ArrayList(), 那么对于使用了ArrayList实现类特有的方法和属性的地方全部都要修改。
List<String> list = new ArrayList<String>()用到了泛型和多态:多态上面已经解释,泛型下一节会写到。
3.5 ArrayList与LinkedList的比较
ArrayList和数组类似,也是线性顺序排列,可理解成可变容量的数组。如果需要根据索引位置访问集合中的素,那么线性顺序存储方法的效率较高,但如果向ArrayList中插入和删除素,则数度较慢,因为在插入(删除)指定索引位置上的素时,当前素及之后的素都要相应的向后移动一位(或之后的素向前移动一位),从而影响对集合的操作效率。
LinkedList在实现中采用链表数据结构,相比于ArrayList,LinkedList访问速度较慢,但插入和删除熟读块,主要原因在于插入和删除素时,只需要修改相应的链接位置,不需要移动大量的素。
Vector是Java旧版本中集合的实现,它与ArrayList的操作几乎一样,但Vector是线程安全的动态数组。
四、Set集合
4.1 Set接口
List集合按照对象的插入顺序保存对象,Set集合的对象不按照顺序保存对象,可以说是不完全无序状态。
Set集合中的对象没有按照特定的方式排序,仅仅简单地将对象加入其中,但是集合中不能存放重复对象。由于Set接口实现了Collection接口,所以Set接口有Collection接口提供的所有常用方法。
4.2 HashSet类
HashSet是Set集合最常用的实现类,它按照Hash算法来存储集合中的素,根据对象的哈希码确定对象的存储位置,具有良好的存取和查找性能。HashSet类的主要方法有:
4.2.1 HashSet类的常用方法
方法 |
说明 |
boolean add(E e) |
向集合中添加集合中没有的素 |
void clear() |
移除集合中所有的素 |
boolean contains(Object o ) |
如果集合中包含指定素,返回true |
boolean isEmpty() |
如果为空集合,则返回true |
Iterator iterator() |
返回此集合中素进行迭代的迭代器 |
boolean remove(Object o) |
删除指定素 |
int size() |
返回集合中素数量 |
4.2.2 HashSet类的常用方法举例
HashSet类的实现:
public class Example8_8 { public static void main(String[] args) { HashSet hashSet = new HashSet(); hashSet.add("a"); hashSet.add("null"); hashSet.add("b"); hashSet.add("c"); hashSet.add("d"); System.out.println("集合中的素为:"+hashSet); hashSet.remove("b"); System.out.println("集合中是否包含b素:"+hashSet.contains("b")); Object[] objects = hashSet.toArray(); System.out.print("数组中的素为:"); for (Object o:objects){ System.out.print(o); } hashSet.clear(); System.out.println("\n"+"集合中是否不包含任何素:"+hashSet.isEmpty()); } } 复制代码
编译和运行后的结果为:
集合中的素为:[a, b, c, null, d] 集合中是否包含b素:false 数组中的素为:acnulld 集合中是否不包含任何素:true 复制代码
可以看到HashSet中的素没有按照顺序进行存储,并且可以为null,null的个数只有一个;重复向HashSet中添加素,其值只显示一次。
Set集合中不允许重复的素存在,当向集合中插入对象时,如何判别在集合中是否已经存在该对象?
查看源码可知:当向HashSet对象添加新对象时,Java系统先调用对象的hashCode()方法来获取该对象的哈希码,如何根据哈希码找到对应的存储区域。如果该存储区域已经有了对象,则调用equals()方法与新素进行比较,相同就不保存,不同就放在其它地址。
针对用户自行定义的对象,需要重写hashCode()和equals()方法才能避免重复添加对象,保证程序的正常运行。
4.3 TreeSet接口
4.3.1 TreeSet类的常用方法
TreeSet集合中的素处于排序状态,主要按照红黑树的数据结构来存储对象。TreeSet提供了一些额外的方法。
方法 |
类型 |
说明 |
TreeSet() |
构造 |
构造一个空Set对象,Set根据素的自然顺序进行排序 |
TreeSet(Collectio c) |
构造 |
用类c的与那苏初始化Set |
TreeSet(Comparator comparator) |
构造 |
按照comparator指定的比较方法进行排序 |
TreeSet(SortedSet s) |
构造 |
构造了一个包含s素的set |
Object first() |
普通 |
返回Set中排序为第一个的素 |
Object last() |
普通 |
返回Set中排序为最后一个的素 |
E lower(E e) |
普通 |
返回此Set中严格小于给定素的最大素,如果不存在则返回null |
E higher(E e) |
普通 |
返回此Set中严格大于给定素的最大素,如果不存在则返回nul |
SortedSet subSet(E fromElement, E toElement) |
普通 |
返回有序集合,其素范围为[fromElement,toElement) |
SortedSet headSet(E toElement) |
普通 |
返回此Set的部分集合,其素范围为[, toElement)小于toElement |
SortedSet tailSet(E fromElement) |
普通 |
返回此Set的部分集合,其素范围为[fromElement ,]大于等于toElement |
4.3.2 TreeSet类的常用方法举例
利用TreeSet方法对集合中的素进行操作。
class Example8_9 { public static void main(String[] args) { TreeSet treeSet = new TreeSet(); TreeSet treeSet1 = new TreeSet(); treeSet.add(10); treeSet.add(3); treeSet.add(8); treeSet.add(0); treeSet1.add("b"); treeSet1.add("k"); treeSet1.add("z"); treeSet1.add("a"); //输出集合素,看到集合已经处于排序状态 System.out.println("treeSet集合中的素"+treeSet); System.out.println("treeSet1集合中的素"+treeSet1); System.out.println("treeSet集合中的第一个素:"+treeSet.first()+",treeSet集合中的最后一个素:"+treeSet.last()); System.out.println("treeSet1集合中的第一个素:"+treeSet1.first()+",treeSet1集合中的最后一个素:"+treeSet1.last()); //返回集合中小于5的集合,不包含5; System.out.println(treeSet.headSet(5)); //返回集合中小于c的集合 System.out.println(treeSet1.headSet("c")); //返回大于等于8的集合 System.out.println(treeSet.tailSet(8)); //返回大于等于9,小于11的集合 System.out.println(treeSet.subSet(9,11)); } } 复制代码
编译和运行后的结果为:
treeSet集合中的素[0, 3, 8, 10] treeSet1集合中的素[a, b, k, z] treeSet集合中的第一个素:0,treeSet集合中的最后一个素:10 treeSet1集合中的第一个素:a,treeSet1集合中的最后一个素:z [0, 3] [a, b] [8, 10] [10] 复制代码
从上面的运行结果来看,TreeSet根据素的实际大小进行排序,不同于List是按照素插入顺序进行排序。
TreeSet排序通用规则:若为数值,按照大小;若为字符,按照字符对应的Unicode值排序;如果是日期、时间,按照时间顺序排序;如果是boolean,true大于false
4.4 Set实现类性能分析
TreeSet集合中素唯一且已经排好序,采用额外的红黑树算法进行排序,如果需要一个保持顺序的集合时,应该选择TreeSet;
HashSet集合中素唯一且已经排好序,它按照Hash算法进行排序,如果经常对素进行添加、查询操作,应该选择HashSet;
LinkedHashSet是HashSet的一个子类,具有HashSet的特性,也是根据素的hashCode值来确定素的存储位置,它使用链表维护素的次序,因此插入和删除性能比HashSet低,迭代访问集合中全部素时性能高。
五、Queue队列
5.1 Queue接口
Queue接口是一个先入先出(FIFO)的数据结构,继承Collection接口,LinkedList(双向链表)实现了List和Deque接口。
5.2 Deque接口和ArrayDeque类
Deque接口是Queue接口的子接口, Deque接口的实现类主要是LinkedList类(前面已学习)和ArrayDeque类。
ArrayDeque类是使用可变循环数组来实现双端队列,该容器不允许放入null素。
5.2.1 Deque接口和ArrayDeque类常用方法
方法 |
说明 |
boolean add(E e) |
将素e插入此双端队列末尾 |
void addFirst(E e) |
将素e插入此双端队列开头 |
void addLast(E e) |
将素e插入此双端队列末尾 |
void clear() |
删除队列中所有素 |
boolean contains(Object o) |
判断是否包含指定素 |
element() |
获取队列中的头 |
getFirst() |
获取队列中第一个素 |
getLast() |
获取队列中最后一个素 |
boolean offer(E e) |
将素e插入此双端队列末尾 |
boolean offerFirst(E e) |
将素e插入此双端队列开头 |
boolean offerLast(E e) |
将素e插入此双端队列末尾 |
removeFirst() |
获取并且删除队列中第一个素 |
removeLast() |
获取并且删除队列中最后一个素 |
int size() |
返回队列中所有素数量 |
5.2.2 Deque接口和ArrayDeque类常用方法举例
class Example8_10 { public static void main(String[] args) { ArrayDeque arrayDeque = new ArrayDeque(); arrayDeque.addFirst("b"); arrayDeque.offerFirst("k"); arrayDeque.addLast("z"); arrayDeque.add("a"); //输出集合素,看到集合已经处于排序状态 System.out.println("arrayDeque队列中的素"+arrayDeque); System.out.println("arrayDeque队列中是否包含c:"+arrayDeque.contains("c")); System.out.println(arrayDeque.removeFirst());//删除第一个素 System.out.println("arrayDeque队列的首素:"+arrayDeque.element()); System.out.println("arrayDeque队列的首素:"+arrayDeque.getFirst()); System.out.println("arrayDeque队列的素个数:"+arrayDeque.size()); } } 复制代码
编译和运行后的结果为:
arrayDeque队列中的素[k, b, z, a] arrayDeque队列中是否包含c:false k arrayDeque队列的首素:b arrayDeque队列的首素:b arrayDeque队列的素个数:3 复制代码
5.3 PriorityQueue类
PriorityQueue(优先队列)是Queue接口的实现类,其底层是堆实现的。每次插入或删除素后都对队列进行调整,队列始终构成最小堆或最大堆。
5.3.1 PriorityQueue类常用方法
方法 |
说明 |
boolean add(E e) |
插入指定素到此优先队列 |
boolean offer(E e) |
插入指定素到此优先队列 |
void clear() |
删除所有素 |
boolean contains(Object o) |
是否包含指定素 |
peek() |
获取此优先队列的头,队列为空返回null |
poll() |
获取并且删除此优先队列的头,队列为空返回null |
boolean remove(Object o) |
删除指定素 |
int size() |
返回此优先队列素个数 |
5.3.2 PriorityQueue类常用方法举例
class Example8_11 { public static void main(String[] args) { PriorityQueue priorityQueue = new PriorityQueue(); priorityQueue.add(3); priorityQueue.offer(7); priorityQueue.add(1); priorityQueue.add(4); System.out.println("priorityQueue队列中的素" + priorityQueue); System.out.println("priorityQueue队列中是否包含2:" + priorityQueue.contains(2)); System.out.println("priorityQueue队列的首素:" + priorityQueue.peek()); System.out.println("priorityQueue队列的首素:" + priorityQueue.poll()); System.out.println("删除素后,arrayDeque队列的素:"+priorityQueue); priorityQueue.remove(7); System.out.println("删除素后,arrayDeque队列的素:"+priorityQueue); System.out.println("arrayDeque队列的素个数:" + priorityQueue.size()); } } 复制代码
编译和运行后的结果为:
priorityQueue队列中的素[1, 4, 3, 7] priorityQueue队列中是否包含2:false priorityQueue队列的首素:1 priorityQueue队列的首素:1 删除素后,arrayDeque队列的素:[3, 4, 7] 删除素后,arrayDeque队列的素:[3, 4] arrayDeque队列的素个数:2 复制代码
六、Map集合
6.1 Map接口
Map集合用于保存具有映射关系的数据,在Map集合中保存着两组值,一组值是key键,另一组值是value值。key和value之间存在一对一的关系,通过指定的key键就能找到唯一的value值。Map中的key键不允许重复(key键唯一),value值可以重复。
6.1.1 Map接口常用方法
方法 |
说明 |
put(K key, V value) |
向集合中添加指定的键——值映射关系 |
void putAll(Map<? extends K, ? extends V> m) |
向集合中添加指定集合中所有的键——值映射关系 |
boolean containsKey(Object key) |
判断此集合中是否包含指定的键映射关系 |
boolean containsValue(Object value) |
判断此集合中是否包含指定的值映射关系 |
V get(Object key) |
返回指定的键所映射的值,否则返回null |
Set keySet() |
以Set集合的形式返回该集合中的所有键对象 |
Collection values() |
以Collection集合的形式返回该集合中的所有值对象 |
V remove(Object key) |
删除并返回键对应的值对象 |
void clear() |
清空集合中所有的映射关系 |
boolean isEmpty() |
判断集合是否为空 |
int size() |
返回集合中键——值映射关系的个数 |
boolean equals(Object o) |
比较指定的键——值映射关系是否相等 |
6.1.2 Map接口常用方法举例
class Example8_12 { public static void main(String[] args) { Map map1 = new HashMap<>(); Map map2 = new HashMap<>(); Map map3 = new HashMap<>(); map1.put(1001, "Bill"); map1.put(1002, "a"); map1.put(null, null); map2.put(1003, "B"); map2.put(100, "C"); map3.put(100, "C"); map3.put(1003, "B"); System.out.println("map1的对象为:" + map1); System.out.println("map2的对象为:" + map2); map1.putAll(map2); System.out.println("map1的对象为:" + map1); System.out.println("map1是否包含键对象null:" + map1.containsKey(null)); System.out.println("map1是否包含\"a\"值:" + map1.containsValue("a")); System.out.println("map1的键1001的对象为:" + map1.get(1001)); System.out.println("map1的键对象为:" + map1.keySet()); System.out.println("map1的值对象为:" + map1.values()); System.out.println("删除1003键对象后,map1的值对象为:" + map1.remove(1003) + "," + map1); map1.clear(); System.out.println("map1的值对象为:" + map1); System.out.println("map1是否为null:" + map1.isEmpty()); System.out.println("map2的大小:" + map2.size()); System.out.println("map2和map3是否是一个对象:" + map2.equals(map3)); } } 复制代码
编译和运行后的结果为:
map1的对象为:{null=null, 1001=Bill, 1002=a} map2的对象为:{100=C, 1003=B} map1的对象为:{null=null, 100=C, 1001=Bill, 1002=a, 1003=B} map1是否包含键对象null:true map1是否包含"a"值:true map1的键1001的对象为:Bill map1的键对象为:[null, 100, 1001, 1002, 1003] map1的值对象为:[null, C, Bill, a, B] 删除1003键对象后,map1的值对象为:B,{null=null, 100=C, 1001=Bill, 1002=a} map1的值对象为:{} map1是否为null:true map2的大小:2 map2和map3是否是一个对象:true 复制代码
可以看到:在Map集合中,值对象可以是null,并且不限制个数,因此get()方法的返回值为null时,可能在该集合中没有该键对象,也可能键对象没有对应的映射值。要判断是否存在某个键时,要使用containsKey()方法。
6.2 HashMap类
6.2.1 HashMap介绍
HashMap实现了Map接口,因此HashMap有Map接口提供的所有常用方法。同HashSet类似,HashMap不能保证素的顺序。
HashMap的底层实现采用了哈希表,JDK1.8之前,哈希表实质上是“ "的形式,如下图:
键值对的存放和查询采用的是Hash算法,当添加严格素(key-value)时,首先计算素key的Hash值,以此确定插入数组中的位置。有可能存在同一Hash值的素已经被放在数组的同一位置了,这时就添加到同一Hash值素的后面,他们在数组的同一位置,但是形成了链表,同一个链表上的Hah值时相同的,所以说数组存放的是链表。JDK8中,当链表的长度大于8时,链表就转换成为红黑树,这样就提高了查找素的效率。
6.2.2 HashMap类常用方法举例
public class Example8_13 { public static void main(String[] args) { Map map = new HashMap(); map.put(109, "PS"); map.put(107, "c语言"); map.put(108, "Js"); map.put(99, "数据结构"); map.put(99, "Java程序设计");//存在相同的key时,后插入的会被覆盖 System.out.println(map); Map map1 = new HashMap<>(); map1.put(1001, "Bill"); map1.put(1001, "Bi");//存在相同的key时,后插入的会被覆盖 System.out.println(map1); System.out.println(map.containsKey(99)); for(Object o:map.keySet()){ System.out.println(o+"-->"+map.get(o)); } } } 复制代码
编译和运行后的结果为:
{99=Java程序设计, 107=c语言, 108=Js, 109=PS} {1001=Bi} true 99-->Java程序设计 107-->c语言 108-->Js 109-->PS 复制代码
6.3 TreeMap类
6.3.1 TreeMap类常用方法
TreeMap是Map接口的主要实现类,TreeMap存放的是有序数据,按照key进行排序。TreeMap底层采用红黑树(红黑树的每个节点就是一个key-value对)对key-value进行排序。
TreeMap类的主要方法如下:
方法 |
类型 |
说明 |
TreeMap() |
构造方法 |
使用键的自然顺序构造一个新的、空的树映射 |
TreeMap(Map<? extends K, ? extends V> m) |
构造 |
构造一个与给定映射具有相同映射关系的新的树映射,该映射根据其键的自然顺序排序 |
TreeMap(Comparator<? super K> comparator) |
构造 |
构造一个新的、空的树映射,该映射根据给定的比较器进行排序 |
TreeMap(SortedMap<K, ? extends V> m) |
构造 |
构造一个与给定有序映射具有相同映射关系和相同排序顺序的新的树映射 |
Comparator<? super K> comparator() |
普通 |
返回对此映射中的键进行排序的比较器;如果此映射使用键的自然顺序,则返回null |
K firstKey() |
普通 |
返回此映射中当前第一个键 |
K lastKey() |
普通 |
返回此映射中当前最后一个键 |
SortedMap<K,V> headMap(K toKey) |
普通 |
返回此映射中部分视图,其键值小于toKey |
SortedMap<K,V> subMap(K fromKey, K toKey) |
普通 |
返回此映射中部分视图,其键值小于toKey大于等于fromKey |
SortedMap<K,V> tailMap(K fromKey) |
普通 |
返回此映射中部分视图,其键值大于等于fromKey |
6.3.2 TreeMap类常用方法举例
public class Example8_14{ public static void main(String[] args) { TreeMap treeMap = new TreeMap(); treeMap.put(10,"a"); treeMap.put(1,"a"); treeMap.put(9,null); treeMap.put(5,"c"); treeMap.put(3,null); System.out.println(treeMap); System.out.println(treeMap.lastKey()); System.out.println(treeMap.headMap(2)); System.out.println(treeMap.tailMap(2)); TreeMap treeMap1 = new TreeMap(treeMap); System.out.println(treeMap1); } } 复制代码
输出结果为:
{1=a, 3=null, 5=c, 9=null, 10=a} 10 {1=a} {3=null, 5=c, 9=null, 10=a} {1=a, 3=null, 5=c, 9=null, 10=a} 复制代码
6.4 TreeMap和HashMap性能比较
HashMap没有按照键值大小输出,如果需要对key-value进行插入、删除操作,优先使用 HashMap;
TreeMap按照键值大小输出,,针对需要排序的Map,优先使用TreeMap。
七、总结各集合类之间对比
Arraylist |
LinkedList |
HashSet |
TreeSet |
ArrayDeque |
PriorityQueue |
HashMap |
TreeMap |
是否有序 |
有序 |
有序 |
无序 |
有序 |
有序 |
有序 |
无序 |
存储结构 |
集合 |
集合 |
集合 |
集合 |
集合 |
集合 |
键值对 |
线程安全 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
素是否有重复 |
是 |
是 |
否 |
否 |
是 |
是 |
键值唯一,相同覆盖 |
素是否可为null |
是 |
是 |
是 |
是 |
否 |
否 |
是 |
底层数据结构 |
数组 |
链表 |
哈希表 |
二叉树 |
循环数组 |
堆 |
哈希表 |
特点 |
查询快,增删慢 |
查询慢,增删快 |
快速查找 |
快速排序 |
查询快,增删慢 |
/ |
插入、删除和定位素快 |
作者:Pandafz
链接:https://juejin.cn/post/
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://sigusoft.com/bj/4697.html