21.集合的使用

集合

应用场景

  • 无法预测存储数据的数量
  • 同时存储具有一对一关系的数据
  • 需要进行数据的增删
  • 数据重复问题

体系结构

在这里插入图片描述

Conlection

Collection 接口有 3 种子类型集合: ListSetQueue,再下面是一些抽象类,最后是具体实现类,常用的有 ArrayList、LinkedList、HashSet、LinkedHashSet、ArrayBlockingQueue等。

List

  • List是元素有序并且可以重复的集合,称为序列
  • List可以精确的控制每个元素的插入位置,或删除某个位置的元素
  • List的两个主要实现类是ArrayList和LinkedList
ArrayList
  • 底层是由数组实现的
  • 动态增长,以满足应用程序的需求
  • 在列表尾部插入或删除数据非常有效
  • 更适合查找和更新元素
  • ArrayList的元素可以为null

示例:创建一个列表,向里面装入元素,并输出元素个数。

		List list = new ArrayList();
		// add()向列表中添加元素
		list.add("Java");
		list.add("C");
		list.add("C ++");
		list.add("Go");
		list.add("C#");
		list.add("JavaScript");
		// size()输出元素个数
		System.out.println("列表中元素个数:" + list.size());

示例:遍历列表中元素。

		for(int i = 0; i < list.size(); i ++) {
			// 通过ger(i)下标获取列表中对应位置的元素
			System.out.println(list.get(i));
		}

示例:移除列表中的元素。

		list.remove(3);	// 可以通过下标移除
		list.remove("Go");	// 也可以根据值移除

案例:公告管理
需求:

  • 公告的添加和显示
  • 在指定位置插入公告
  • 删除公告
  • 修改公告
		// 创建Notice对象
		Notice notice1 =new Notice(1, "第一条", "作者1", new Date());
		Notice notice2 =new Notice(2, "第二条", "作者2", new Date());
		Notice notice3 =new Notice(3, "第三条", "作者3", new Date());
		Notice notice4 =new Notice(4, "第四条标题", "作者4", new Date());
		
		// 添加公告列表
		ArrayList noticeList = new ArrayList();
		noticeList.add(notice1);
		noticeList.add(notice2);
		noticeList.add(notice3);
		noticeList.add(notice4);

		// 在第一条后面添加一条新公告
		Notice notice5 = new Notice(5, "添加的信息", "管理员", new Date());
		noticeList.add(1, notice5);
		
		// 删除第三条公告
		noticeList.remove(4);
		
		// 將第一條公告title修改为 :最先发布的消息
		notice1.setTitle("最先发布的消息");
		noticeList.set(0, notice1);	// 此处没有创建新的对象,可以不使用set方法,如果需要用新的对象来设置,则可以使用set方法修改
		
		// 显示公告
		System.out.println("公告内容为:"); 
		for(int i = 0; i < noticeList.size(); i ++) {
			System.out.println(i + 1 + ": " +((Notice) noticeList.get(i)).getTitle());
		}
注意
  • ArrayList实现了List接口,LinkedList实现了List接口,同时实现了Queue接口
  • ArrayList的底层是数组,因此在内存中是连续存储的,查询速度快,但增加和删除速度慢
  • LinkedList底层是基于双向链表,增加和删除速度快,而查询速度慢

Set

Set是元素无序并且不可以重复的集合,被称为集。

HashSet
  • HashSet是Set的一个重要实现类,被称为哈希集
  • HashSet中的元素无需并且不可以重复
  • HashSet中只允许一个null元素
  • 具有良好的存取和查找性能
hashCode与equals方法的作用

hashCode()方法用于返回对象的hash code值,equals()方法用于 判断其他对象与对象是否相等

为何要用这两种方法?

  • 首先,HashSet里是不允许重复添加元素的,当调用add()方法向HashSet添加元素时,是通过hashCode()equals()方法
  • 在添加数据时,会调用hashCode()方法,得到hash code值,通过这个值找到数据存储的位置,可以理解为存储的区域,在这个区域存储的hash code值是相等的
  • 如果这个区域已经有数据了,就继续调用equals()方法判断数据是否相等,如果相等则说明数据重复了,则不嫩个添加,如果不相等,就可以找到一个位置存储。
  • 如果两个对象相等,那么他们的hashCode()值一定相等。反之,如果两个对象的hashCode()相等,那么他们不一定相等,还需要使用equals()方法比较判断。

注意:

  • 这些都是基于哈希算法完成的,它使得添加数据的效率得到了提升,假如Set集合中已经有100个元素,如果此时没有使用哈希算法,就需要调用equals()方法将第101个元素与前100个元素依次进行比较,如果元素更多,比较耗费时间就越长。
  • 如果不重写hashCode()方法,默认每个对象的hashCode()值都不一样,所以该类的每个对象都不会相等
Iterator(迭代器)
  • Iterator接口可以以统一的方式对集合元素进行遍历
  • hasNext()方法检测集合中是否还有下一个元素
  • next()方法返回集合中的下一个元素

案例:用HashSet存储多个表示颜色的英文单词,并输出。

		// 创建set集合对象
		Set set = new HashSet();
		// 向集合中添加元素
		set.add("blue");
		set.add("red");
		set.add("black");
		set.add("green");
		set.add("yellow");
		// 创建迭代器,是一种用于访问集合的方法,可用于迭代 ArrayList 和 HashSet 等集合
		Iterator it = set.iterator();
		// 遍历迭代器输出元素 
		while(it.hasNext()) {	// 通过hasNext()判断如果迭代具有更多的元素,则返回true
			System.out.println(it.next());	// 返回迭代中的下一个元素。
		}
		
		set.add("green");	// 重复元素添加不会添加成功,也不会报错

案例:宠物猫信息管理
需求

  • 添加和显示宠物猫的信息
  • 查找某只宠物猫的信息并输出
  • 修改宠物猫的信息
  • 删除宠物猫的信息

Cat类

package com.listutil.com;

public class Cat {
	private String name;	// 姓名
	private int month;	// 年龄
	private String species;		// 品种
	
	// 构造方法
	public Cat(String name, int month, String species) {
		this.setName(name);
		this.setMonth(month);
		this.setSpecies(species);
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getMonth() {
		return month;
	}

	public void setMonth(int month) {
		this.month = month;
	}

	public String getSpecies() {
		return species;
	}

	public void setSpecies(String species) {
		this.species = species;
	}

	@Override
	public String toString() {
		return "[姓名=" + name + ", 年龄=" + month + ", 品种=" + species + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + month;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result + ((species == null) ? 0 : species.hashCode());
		return result;
	}

	/**
	
	@Override
	public boolean equals(Object obj) {
		if(this == obj)
			return true;
		// 反射,判断是否属于Cat类
		if(obj.getClass() == Cat.class) {
			Cat cat = (Cat)obj;	
			return cat.getName().equals(name) && (cat.getMonth() == month) && cat.getSpecies().equals(species);
		}
		return false;
	}
	

}

测试类


	public static void main(String[] args) {

		Cat huahua = new Cat("花花", 2, "波斯猫");
		Cat fanfan = new Cat("凡凡", 1, "英短");
		Cat huahua1 = new Cat("花花2代", 1, "波斯猫");
		
		// 将宠物猫对象放入HashSet中
		Set<Cat> set = new HashSet<Cat>();
		set.add(huahua);
		set.add(fanfan);
		set.add(huahua1);
		
		// 查找宠物猫信息
		// 1. 通过对象名查找 huahua
		if(set.contains(huahua)) {
			System.out.println("通过对象名查找\"huahua\"找到了:");
			System.out.println(huahua);
		}else {
			System.out.println("没找到\"huahua\"");
		}
		
		
		// 2. 通过集合中的名字信息查找 “花花”
		Iterator<Cat> it = set.iterator();
		boolean flag = false;
		Cat c = null;
		while(it.hasNext()) {
			c = it.next();	// 引入泛型去掉了强制类型转换
			if(c.getName().equals("花花")) {
				flag = true;
				break;
			}
		}
		if(flag) {
			System.out.println("通过集合查找姓名\"花花\"找到了:");
			System.out.println(c);
		}

		
		// 删除花花2代信息
		for(Cat cat : set) {
			if("花花2代".equals(cat.getName())) {
				set.remove(cat);break;
			}
		}
		
		// 删除年龄小于2的
		Set<Cat> set1 = new HashSet<Cat>();
		for(Cat cat : set1) {
			if(cat.getMonth() < 2) {
				set1.add(cat);
			}
		}
		set.removeAll(set1);
		
		
		// 遍历输出
		for(Cat cat : set) {
			System.out.println(cat);
		}

}
注意
  • Set接口的主要实现类有HashSetTreeSet
  • HashSet是基于哈希表实现的,数组是无序的,HashSet元素可以是null,但只能有一个
  • TreeSet是基于二叉树实现的,可以实现数据的自动排序,确保集合元素处于排序状态,不允许放入空值
  • HashSet的性能优于TreeSet,一般情况建议使用HashSet,如果需要使用排序功能建议使用TreeSet

Map

  • Map中的数据是以键值对(key-value)的形式存储的
  • key-value以Entry类型的对象实例存在
  • 可以通过key值快速地查找value
  • 一个映射不能包含重复的键
HashMap
  • 基于哈希表的Map接口的实现
  • 允许使用null值和null键
  • key值不允许重复
  • HashMap中的Entry对象是无需排列的

案例:完成一个类似字典的功能
需求:

  • 将单词以及单词的注释存储到HashMap中
  • 显示HashMap中的内容
  • 查找某个单词的注释并显示
	public static void main(String[] args) {

		// 创建HashMap对象
		HashMap<String, String> map = new HashMap<String, String>();
		
		// 添加数据,map用put(key, value)方法添加key和value值
		map.put("cat","猫");
		map.put("dog","狗");
		map.put("snake","蛇");
		map.put("fire","火");

		// 打印输出value的值
		System.out.println("遍历输出value数据");
		Iterator<String> it = map.values().iterator();
		while(it.hasNext()) {
			System.out.print(it.next() + " ");
		}
		
		// 打印输出key和value的值
		System.out.println("通过entrySet方法得到key-value:");
		// 	entrySet()方法返回一个映射的Set视图。
		Set<Entry<String, String>> entrySet = map.entrySet();
		for(Entry<String, String> entry : entrySet) {
			System.out.print(entry.getKey() + "-");
			System.out.println(entry.getValue());
		}
		System.out.println("********************");
		
		// 通过单词查找注释并输出
		System.out.println("请输入查找的单词:");
		Scanner sc = new Scanner(System.in);
		String strSearch = sc.next();
		// 1.取得keySet,,返回包含的键的Set视图。
		Set<String> keySet = map.keySet();
		// 2.遍历keySet
		boolean flag = false;
		HashMap<String, String> wordMap = new HashMap<String, String>();
		String k = null;
		for(String key : keySet) {
			if(strSearch.equals(key)) {
				flag = true;
				k = key;
				wordMap.put(key, map.get(key));
				break;
			}
		}
		if(flag)
			System.out.println("找到:" + k + ":" + wordMap.get(k));
		else
			System.out.println("没找到");
	}

案例2:商品信息管理

  • 使用HashMap对商品信息进行管理
  • 其中key为商品编号,value为商品对象
  • 对HashMap中的商品信息进行增、删、改、查操作

Goods

public class Goods {

	private String id;	// 商品编号
	private String name;	// 商品名称
	private double price;	// 商品价格
	
	public Goods(String id, String name, double price) {
		this.setId(id);
		this.setName(name);
		this.setPrice(price); 
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	@Override
	public String toString() {
		return " [商品编号=" + id + ", 商品名称=" + name + ", 商品价格=" + price + "]";
	}
}

测试类

public class GoodsTest {

	public static void main(String[] args) {

		// 定义HashMap对象
		HashMap<String, Goods> goodsMap = new HashMap<String, Goods>();
		// 装入商品信息
		// if(goodsMap.containsKey(key))判断key是否存在,保证key值的唯一
		goodsMap.put("s0001", new Goods("s0001", "棒棒糖", 2.5));
		goodsMap.put("s0002", new Goods("s0002", "巧克力", 5));
		goodsMap.put("s0003", new Goods("s0003", "饼干", 7.5));
		goodsMap.put("s0004", new Goods("s0004", "卫龙辣条", 4.5));
		

		// 增加商品
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入商品编号:");
		String goodsId;
		while(true) {
			goodsId = sc.next();
			// 查询map里是否包含key值
			if(goodsMap.containsKey(goodsId)) {
				System.out.println("该商品编号已经存在,请重新输入!");
				continue;
			}else
				break;
		}
		System.out.println("请输入商品名称:");
		String goodsName = sc.next();
		System.out.println("请输入商品价格:");
		double goodPrice = 0;
		while(true) {
			try {
				goodPrice = sc.nextDouble();
				break;
			}catch(InputMismatchException e) {
				System.out.println("商品价格格式输入不正确,请输入数值型数据");
				sc.next();	//	错误数据放到这个next()里
				continue;
			}
		}
		goodsMap.put(goodsId, new Goods(goodsId, goodsName, goodPrice));

		// 删除商品
		System.out.println("请输入要删除的商品名称:");
		String deleteName = sc.next();
		// 通过keySet()返回此地图中包含的键的Set视图
		for(String key : goodsMap.keySet()) {
			// 比较元素的name是否符合要删除的商品名称
			if(goodsMap.get(key).getName().contains(deleteName)) {
				goodsMap.remove(key);
			}
		}
		
		
		// 修改商品名称
		System.out.println("请选择要修改的商品:");
		String oldName = sc.next();
		if(goodsMap.containsValue(oldName)) {
			for(String key : goodsMap.keySet()) {
				// 比较元素的name是否符合要删除的商品名称
				if(goodsMap.get(key).getName().contains(oldName)) {
					Goods oldGood = goodsMap.get(key);
					System.out.println("请输入修改的商品名称:");
					String newName = sc.next();
					oldGood.setName(newName);
					goodsMap.replace(key, oldGood);
				}
			}
		}else {
			System.out.println("没有找到该商品");
		}
		
		
		// 遍历商品信息
		Iterator it1 = goodsMap.values().iterator();
		while(it1.hasNext()) {
			System.out.println(it1.next());
		}
	}
注意
  • Map的主要实现类包括HashMap和TreeMap,其中HashMap基于哈希表实现,TreeMap基于红黑树实现
  • HashMap适用在Map中插入、删除和定位元素
  • TreeMap适用于自然顺序或自定义顺序对键值进行遍历
  • HashMap比TreeMap性能好,所以HashMap使用更多一些,如果需要好对数据进行排序可以使用TreeMap
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

空 白

停止的只会是自己,你得追逐世界

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值