Java中的集合:List、Set、Map集合详解

导读:本篇文章讲解 Java中的集合:List、Set、Map集合详解,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

一、关于集合的背景概况

1、为什么会产生集合?
集合可以类比到数组,都是储存多个数据的容器。
数组:长度不可变,在定义时就已经指定其长度(巴士)
集合:长度可变(火车,可以加车厢)
所以,在使用层面上来说,使用集合会比使用数组更加便利。
2、集合类概述
在这里插入图片描述
说明:
Collection是List和Set的父接口
List和Set同样也是接口
List常用的实现类:ArrayList和LinkedList
Set常用的实现类:HashSet和TreeSet

Map常用的实现类:HashMap和TreeMap

小知识:
Collection(集合名称) Collections(操作集合的工具类)
Array(数组名称) Arrays(操作数组的工具类)

说明:
首先,我们必须明确一点,以下所谈有序和无序不是指集合中的排序,而是指是否按照元素添加的顺序来存储对象。

二、List集合

List集合的特点:有序,可以有重复的元素。
常用实现类:ArrayList和LinkedList

1、ArrayList和LinkedList对比

(1)ArrayList集合
具有数组结构的list集合,有下标,可以通过下标查找、删除、修改、添加集合中的元素,下标和数组一样从0开始。
与数组对比: ArrayList集合的长度是可以改变的,添加元素和删除元素是不需要手动扩容和缩容的。

(2)LinkedList集合
双向链表结构,没有下标。
在这里插入图片描述
说明: 对于LinkedList集合中的一个元素,除了存放data信息,还存放着上一个元素以及下一个元素的地址信息。

(3)从查询角度看
在这里插入图片描述
(4)从修改角度看
在这里插入图片描述
(5) ArrayList必须是连续的内存空间,LinkedList不需要连续的内存空间。

综上所述:
查询方面:
ArrayList有下标,可以根据下标直接获取元素。
LinkedList没有下标,获取元素需要前后遍历

修改方面:
ArrayList删除和添加元素的机制类似于数组,效率慢。
LinkedList删除和添加元素,只需要断开指定的连接,在断开的地方添加或者修改元素、修改地址信息即可,相对ArrayList要快。

2、List集合常用方法

1、添加元素
集合名.add(o);

2、获取集合长度
集合名.size();

3、获取元素(通过下标)
集合名.get(index);

4、删除元素
集合名.remove(index);
remove的重载方法:
在这里插入图片描述
5、修改元素
集合名.set(index, o);

6、添加元素
例如:在下标为1的位置上插入
集合名.add(index,o);

以上,不管是ArrayList还是LinkedList集合都适合用,
后面会列举一些LinkedList集合特有的方法。

3、ArrayList集合遍历

for以及foreach的遍历方式省略不写。
(1)迭代器遍历
原理:
当获取到对应集合的迭代器时,光标指在集合最开始的那个元素,借助迭代器名.hasNext() 来判断是否有下一个元素,如果有则会返回true,没有则会返回false,即已经取到迭代器的末尾了。同时通过迭代器名.next() 来获取元素。

public class Test {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("123");
		list.add("abc");
		list.add("456");
		//1、根据集合获取对应的迭代器
		Iterator<String> it = list.iterator();
		//2、判断后面还有无元素,如果有则输出,无则跳出循环
		while(it.hasNext()) {
			System.out.println(it.next());
		}
	}
}

(2)lambda表达式
JDK1.8之后的新特性。
演变过程复杂,所以展示其应用即可。

public class Test {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("123");
		list.add("abc");
		list.add("456");
		System.out.println("======第一种======");
		list.forEach(n->System.out.println(n));
		System.out.println("======第二种======");
		list.forEach(System.out::println);
	}
}

4、LinkedList详解

在这里插入图片描述
分析: LinkedList可以看做是List的实现类,也可以看做是Queue的实现类,所以下面会介绍一下Queue。
“节点”

(1)Queue

队列:FIFO(先进先出,类似于在生活中去银行办业务)

演示代码:

Queue<String> de = new LinkedList<String>();

打开Queue类,可以看到有6个方法:

方法名 方法名 作用
add() offer() 添加元素
remove() poll() 获取头元素并删除
element() peek() 获取头元素但不删除
可能会产生异常 不会产生异常 小区别(与底层实现有关)

具体可以参考链接内的内容:
链接: Queue接口分析

(2)Deque

<1>双端队列

两端的元素,既能入队,也能出队。
在这里插入图片描述
演示代码:

Deque<String> de = new LinkedList<String>();

打开Deque类,查看接口中的方法

方法名 方法名 作用
addFirst() offerFirst() 添加头元素
addLast() offerLast() 添加末尾元素
removeFirst() pollFirst() 移除并返回此列表的第一个元素
removeLast() pollLast() 移除并返回此列表的最后一个元素
getFirst() peekFirst() 获取头元素但不删除
getLast() peekLast() 获取末尾元素但不删除
可能会产生异常 不会产生异常(一般推荐使用此列方法) 小区别(与底层实现有关)

还有两个方法:

boolean remove(Object o);//删除第一次出现的元素
boolean removeFirstOccurrence(Object o);///删除最后一次出现的元素

<2>实现栈结构

解释: 如果将Deque限制为只能一端进行入队和出队,就是栈的数据结构的实现。
Stack:栈 :FILO(先进后出)。
对于栈而言,有入栈(push)和出栈(pop)

应用: 涉及餐厅的蒸菜系统,数值转化,括号匹配校验,迷宫求解,汉诺塔递归,最多的是后面的文件处理的一些应用,比如对文件进行修改,要查看修改的日
志,先修改的先打印出来。(有待研究)

三、Set集合

Set集合的特点:无序,不可以有重复的元素。
常用实现类:HashSet和TreeSet(底层涉及到红黑树)
(1)HashSet(散列集合)
(2)TreeSet(存放有序)
底层是对集合进行了排序。
要想指定集合的存放顺序,被排序的对象需要实现Comparable接口,并且实现CompareTo()方法,自定义比较方法。
注意: TreeSet不能添加null值,因为调用到CompareTo()方法时,会出现空指针异常

以下只对由HashSet创建的集合对象进行说明

1、说明无序:

public class Test {
	public static void main(String[] args) {
		Set<String> set = new HashSet<String>();
		set.add("1小幸运");
		set.add("2时间有泪");
		set.add("3空");
		set.add("4昨日青空");
		System.out.println(set);
	}
}

输出结果:
[3空, 4昨日青空, 2时间有泪, 1小幸运]

2、说明不可重复:

public class Test {
	public static void main(String[] args) {
		Set<String> set = new HashSet<String>();
		set.add("1小幸运");
		set.add("2时间有泪");
		set.add("3空");
		set.add("4昨日青空");
		set.add("2时间有泪");
		System.out.println(set);
	}
}

输出结果:
[3空, 4昨日青空, 2时间有泪, 1小幸运]

HashSet保证元素唯一性的比较原理?
当比较两个对象是否一样时,首先比较两个对象的hashcode值:
如果hashcode值相同再调用equals()方法进行比较,如果equals()返回true则判定这两个对象相同。
如果hashcode值不相同,就直接判定两个对象不相同,不会再调用equals()方法。

3、对集合的一些操作

(1)判断set集合中是否包含某个元素
set.contains(o);
(2)删除集合中的元素
set.remove(o);
(3)清空set集合
set.clear();
(4)判断集合中是否有元素
set.isEmpty();
(5)遍历集合
(for,foreach,迭代器,lambda)

四、Map集合

Map集合:Map<K,V>
特点:无序 ,由Key(键)和Value(值)组成。
注意:一个键对应一个值(键值映射),不能有重复的键
PS: 键重复的情况,新的Value会覆盖旧的。

public class Test {
	public static void main(String[] args) {
		Map<Integer,String> map = new HashMap<Integer,String>();
		//1、将元素放入Map集合中
		map.put(1,"人海");
		map.put(1,"远辰");
		System.out.println(map);//{1=远辰}
	}
}

常用的实现类:HashMap(散列的键值对)和TreeMap(树状键值对)

以下只对由HashMap创建的集合对象进行说明

(1)常用方法说明:

public class Test {
	public static void main(String[] args) {
		Map<Integer,String> map = new HashMap<Integer,String>();
		//1、将元素放入Map集合中
		map.put(1,"人海");
		map.put(4,"远辰");
		map.put(2,"误解");
		map.put(3,"不算");
		System.out.println(map);//{1=人海, 2=远辰, 3=误解, 4=不算}
		//也说明了Map集合无序的特性
		
		//2、get(Key):通过键,获取值。
		System.out.println(map.get(2));//误解
		
		//3、containsKey(key):查找map中是否存在某个键
		System.out.println(map.containsKey(4));//true
		
		//4、containsValue(o):查找map中是否存在某个值
		System.out.println(map.containsValue("误解"));//true
	}
}

(2)遍历map集合
<1> 获取主键(key)集合,用Set集合来接收。

why not List?
想想他们的特性,List里面的元素可以重复,但是Set里面的元素无序、不可以重复,更为符合!

public class Test {
	public static void main(String[] args) {
		Map<Integer,String> map = new HashMap<Integer,String>();
		map.put(1,"人海");
		map.put(4,"远辰");
		map.put(2,"误解");
		map.put(3,"不算");
		
		//获取主键(key)集合,用Set集合来接收。
		Set<Integer> set = map.keySet();
		
		System.out.println("=====foreach====");
		for(int i:set) {
			//System.out.println(i);//1 2 3 4
			System.out.println("<"+i+","+map.get(i)+">");
		//<1,人海>
		//<2,误解>
		//<3,不算>
		//<4,远辰>
		}
		
		System.out.println("===迭代器===");
		Iterator it = set.iterator();
		//判断迭代器内是否有下一个元素
		while(it.hasNext()) {
			Object o = it.next();
			System.out.println("<"+o+","+map.get(o)+">");
		//效果同上
		}
	}
}

<2> entrySet()遍历Map
此种方式是将map集合中的key和value整体放在set集合
相当于将map集合整体转换成了set集合

public class Test {
	public static void main(String[] args) {
		Map<Integer,String> map = new HashMap<Integer,String>();
		map.put(1,"人海");
		map.put(4,"远辰");
		map.put(2,"误解");
		map.put(3,"不算");
		//将map集合转换成set集合
		Set<Entry<Integer, String>> set = map.entrySet();
		Iterator<Entry<Integer, String>> it = set.iterator();
		while(it.hasNext()) {
			Map.Entry<Integer, String> entry = it.next();
			//System.out.println("<"+o+","+map.get(o)+">");
			System.out.println("<"+entry.getKey()+","+entry.getValue()+">");
		}
		
		for(Entry entry:set) {
			System.out.println(entry);
		}
		//1=人海
		//2=误解
		//3=不算
		//4=远辰
	}
}

五、三种集合的侧重点

1、List关注的是索引
2、Set关注唯一性,它不允许重复
3、Map关注的是唯一的标识符(KEY)
在这里插入图片描述

六、Collections

1、给集合排序:
Collections.sort(集合名);
2、打乱集合的顺序
Collections.shuffle(集合名)
3、求集合的最大值
Collections.max(集合名);
4、求集合的最小值
Collections.min(集合名);
5、替换
Collections.replaceAll(集合名, oldVal, newVal);

七、提醒自己

注意去学一些算法,要弄懂底层的原理。
递归、排序等等。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/16900.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!