Java学习(86)Java集合——案例:宠物猫信息管理(HashSet增删改查)

需求分析

1. 功能需求

(1) 添加和显示宠物猫信息
(2) 查找某只宠物猫的信息并输出
(3) 修改宠物猫的信息
(4) 删除宠物猫信息

2. 属性

(1) 名字name
(2) 年龄month
(3) 品种species

3. 方法

(1) 构造方法
(2) 获取和设置属性值的方法
(3) 其他方法

创建宠物猫Cat类,定义构造方法,定义get/set方法

public class Cat {
	private String name; //名字
	private int month; //年龄
	private String species;//品种
	
	//构造方法
	public Cat(String name, int month, String species) {
		super();
		this.name = name;
		this.month = month;
		this.species = species;
	}
    //getter与setter方法
	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;
	}
}

主方法内定义宠物猫对象,将宠物猫对象放入HashSet中,显示宠物猫信息。

		// 定义宠物猫对象
		Cat huahua = new Cat("花花", 12, "英国短毛猫");
		Cat fanfan = new Cat("凡凡", 3, "中华田园猫");
		// 将宠物猫对象放入HashSet中
		Set set = new HashSet();
		set.add(huahua);
		set.add(fanfan);
		// 显示宠物猫信息
		Iterator it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}

重写toString方法

需要重写toString方法才能显示猫猫具体信息,否则显示的是猫猫的地址信息(这是因为这里的对象是Object类)。重写toString方法后,it.next()会自动调用toString方法。
可以通过Source → \to Generate toString()…来快速重写toString。

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

再添加一个与花花属性一样的猫

		// 再添加一个与花花属性一样的猫
		Cat huahua01 = new Cat("花花", 12, "英国短毛猫");
		set.add(huahua01);
		System.out.println("**********************************");
		System.out.println("添加重复数据后的宠物猫信息:");
		it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}

这里发现运行结果为:

**********************************
添加重复数据后的宠物猫信息:
[姓名:花花, 年龄:12, 品种:英国短毛猫]
[姓名:花花, 年龄:12, 品种:英国短毛猫]
[姓名:凡凡, 年龄:3, 品种:中华田园猫]

我们发现,这并不符合集合的规则:相同的字符串不允许添加到集合。
解决方法:重写hashCode()和equals()方法,来判断宠物信息是否相等。

hashCode()(哈希表)理解

例如,查找100以内的能被的数据。如果使用ArrayList进行查找,那么将会从头到尾遍历一遍,非常麻烦,而且费时间。使用hashCode()(哈希表)进行处理,哈希表会将100以内的数据分为3个桶,桶里分别装能被1整除的数据、能被2整除的数据和能被3整除的数据,首先会根据规则(即能被1、2或者3整除)判断需要查找的数据在哪个桶内,然后在那个桶内遍历桶里的元素,看是不是在桶内。
上述过程中hashCode()方法负责判断需要查找的数据在哪个桶里边,而equals()方法负责判断桶里哪一个才是我们要找的元素。
hashCode()和equals()大大提高了查询的效率,因此我们要对其进行重写。

重写hashCode()和equals()方法

快捷重写:SourceGenerate hashCode() and equals()
hashCode()内容自动重写,不用管,equals()方法我们得自己写一下。
重写equals()方法的步骤:
``java
@Override
public boolean equals(Object obj) {
//判断对象是否相等,相等则返回true,不用继续比较属性了
if(this==obj)
return true;
//判断obj是否是Cat类的对象
if(obj.getClass()==Cat.class){
Cat cat=(Cat)obj;
return cat.getName().equals(name)&&(cat.getMonth()==month)&&(cat.getSpecies().equals(species));
}
return false;
}

(1) 首先判断对象是否相等,如果对象相等则直接返回true,不用继续比较了。其中this是当前类的对象,obj是传入的对象;
(2) 然后判断obj所对应的对象是否为Cat,如果是Cat类型的对象,则强制转换为Cat类的对象。然后判断名字、年龄和品种是否相等;
重写equals()方法后,再添加一个与花花属性一样的猫后,集合就不会显示重复的内容,也就是添加不进去了,这就符合了Set中不能有重复数据的规则了。

# 查找宠物猫信息
```java
		System.out.println("通过名字查找花花信息");
		boolean flag = false;
		Cat c = null;
		it = set.iterator();
		while (it.hasNext()) {
			c = (Cat)it.next();
			if (c.getName().equals("花花")) {
				flag = true;// 找到了
				break;
			}
		}

我们发现,如果将 c = (Cat)it.next();修改为String c1 = (String)it.next();后编译时报错,但是运行时会报错,显示异常:java.lang.ClassCastException,即类型转换异常,这是因为Cat类型不能转换为String类型,因此我们要加入泛型的概念,加入泛型后就无需进行强制转换了。

加入泛型

泛型设定了在Set(集合)中添加的数据必须是我们所需要的类型。
在CatTest类中修改:

		// 将宠物猫对象放入HashSet中
		Set<Cat> set = new HashSet<Cat>();

		// 显示宠物猫信息
		Iterator<Cat> it = set.iterator();

这样在查找信息时,无需进行强制转换,直接查找即可:

		System.out.println("通过名字查找花花信息");
		boolean flag = false;
		Cat c = null;
		it = set.iterator();
		while (it.hasNext()) {
			c = it.next();
			if (c.getName().equals("花花")) {
				flag = true;// 找到了
				break;
			}
		}

注:这里集合和迭代器都加入泛型<Cat>,这样就限制了集合和迭代器中的数据都是Cat类型的对象了。

删除宠物猫的信息

使用增强型for循环编写(将集合中的Cat类型的数据依次取出)。

		// 删除花花二代的信息并重新输出
		for (Cat cat : set) {
			if ("花花二代".equals(cat.getName())) {
				set.remove(cat);
break;			}
		}
		System.out.println("**********************************");
		
		System.out.println("删除花花二代后的数据");
		for(Cat cat:set){
			System.out.println(cat);
		}

删除集合中的所有宠物猫信息

		//删除集合中的所有宠物猫信息
		System.out.println("**********************************");
		boolean flag1=set.removeAll(set);
		if(flag1){
			System.out.println("猫都不见了。。。");
		}else{
			System.out.println("猫还在。。。");
		}

注:这里 flag1换成 set.isEmpty()也可以。

删除所有年龄小于5个月的小猫

步骤:先建立子集合再删除这个子集合。如果这里不建立子集合直接删除,会导致异常:java.util.ConcurrentModificationException,这是因为不能删除正在读取中的数据。

		// 删除年龄为五个月内的小猫集合
		Set<Cat> set1 = new HashSet<Cat>();
		for(Cat cat:set) {
			if(cat.getMonth()<5) {
				set1.add(cat);
			}
		}
		set.removeAll(set1);
		System.out.println("**********************************");

hashCode和equals方法的作用

hashCode()方法用于给对象返回hash code值,equals方法用于判断其他对象与该对象是否相等。为什么需要这两个方法呢?我们知道HashSet中是不允许添加重复元素的,那么当调用add()方法向HashSet中添加元素时,是如何判断两个元素是不同的呢?这就用到了hashCode()和equals()方法。在添加数据时,会调用hashCode()方法得到hash code值,通过这个值可以找到数据存储位置,该位置可以理解成一片区域,在该区域存储的数据的hashCode值都是相等的。如果该区域已经有数据了,就继续调用equals()方法判断数据是否相等,如果相等就说明数据重复了,就不能再添加了。如果不相等,就找到一个位置进行存储。

这些是基于哈希算法完成的,它使得添加数据的效率得到了提升。假设此时Set集合中已经有100个元素,那么如果想添加第101个元素,如果此时没有使用哈希算法,就需要调用equals()方法将第101个元素与之前100个元素依次进行比较,如果元素更多,比较所耗费的时间就越长。

如果两个对象相等,那么他们的hashCode值一定相等。反之,如果两个对象的hashCode值相等,那么这两个对象不一定相等,还需要使用equals()方法进行判断。

如果不重写hashCode()方法,则默认每个对象的hashCode()值都不一样,所以该类的每个对象都不会相等。

关于getClass()和.class的作用

案例:

@Override
public boolean equals(Object obj){
if(this==obj)
    return true;
if(obj.getClass()==Cat.class)
}

以上代码中的第二个if语句,其中的判断条件中用到了getClass()和.class。

首先,来看一下Class类。在Java中,万事万物皆对象,每个类都有一个相应的Class对象。通过Class类,可以获得一个类的基本信息,比如属性、方法和构造方法等。这些都属于Java反射的内容,在后面的课程中将会学习到。

getClass()是Object类的方法,该方法的返回值类型是Class类,通过getClass()方法可以得到一个Class类的对象。而.class返回的也是Class类型的兑现。所以,如果obj.getClass()和Cat.class返回的内容相等,说明是同一个对象。

既然都可以得到Class的对象,关于getClass()和.class的区别:getClass()方法,有多态能力,运行时可以返回子类的类型信息。.class是没有多态的,是静态解析的,编译时可以确定类型信息。

宠物猫信息管理完整代码

Cat类

package com.study.set;

public class Cat {
	private String name; //名字
	private int month; //年龄
	private String species;//品种
	
	//构造方法
	public Cat(String name, int month, String species) {
		super();
		this.name = name;
		this.month = month;
		this.species = species;
	}
    //getter与setter方法
	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) {
		//判断对象是否相等,相等则返回true,不用继续比较属性了
		if(this==obj)
			return true;
		//判断obj是否是Cat类的对象
		if(obj.getClass()==Cat.class){
			Cat cat=(Cat)obj;
			return cat.getName().equals(name)&&(cat.getMonth()==month)&&(cat.getSpecies().equals(species));
		}
		
		return false;
	}
	
	
}

CatTest类

package com.study.set;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class CatTest {

	public static void main(String[] args) {
		// 定义宠物猫对象
		Cat huahua = new Cat("花花", 12, "英国短毛猫");
		Cat fanfan = new Cat("凡凡", 3, "中华田园猫");
		// 将宠物猫对象放入HashSet中
		Set<Cat> set = new HashSet<Cat>();
		set.add(huahua);
		set.add(fanfan);
		// 显示宠物猫信息
		Iterator<Cat> it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}

		// 再添加一个与花花属性一样的猫
		Cat huahua01 = new Cat("花花", 12, "英国短毛猫");
		set.add(huahua01);
		System.out.println("**********************************");
		System.out.println("添加重复数据后的宠物猫信息:");
		it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}

		System.out.println("**********************************");
		// 重新插入一个新宠物猫
		Cat huahua02 = new Cat("花花二代", 2, "英国短毛猫");
		set.add(huahua02);
		System.out.println("添加花花二代后的宠物猫信息:");
		it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}

		System.out.println("**********************************");
		// 在集合中查找花花的信息并输出
		if (set.contains(huahua)) {
			System.out.println("花花找到了!");
			System.out.println(huahua);
		} else {
			System.out.println("花花没找到!");
		}
		// 在集合中使用名字查找花花的信息
		System.out.println("**********************************");
		System.out.println("通过名字查找花花信息");
		boolean flag = false;
		Cat c = null;
		it = set.iterator();
		while (it.hasNext()) {
			c = it.next();
			if (c.getName().equals("花花")) {
				flag = true;// 找到了
				break;
			}
		}
		if (flag) {
			System.out.println("花花找到了");
			System.out.println(c);
		} else {
			System.out.println("花花没找到");
		}

		// 删除花花二代的信息并重新输出
		for (Cat cat : set) {
			if ("花花二代".equals(cat.getName())) {
				set.remove(cat);
break;			}
		}
		System.out.println("**********************************");
		
		// 删除年龄为五个月内的小猫集合
		Set<Cat> set1 = new HashSet<Cat>();
		for(Cat cat:set) {
			if(cat.getMonth()<5) {
				set1.add(cat);
			}
		}
		set.removeAll(set1);
		System.out.println("**********************************");
		
		System.out.println("删除花花二代后的数据");
		for(Cat cat:set){
			System.out.println(cat);
		}
		//删除集合中的所有宠物猫信息
		System.out.println("**********************************");
		boolean flag1=set.removeAll(set);
		if(set.isEmpty()){
			System.out.println("猫都不见了。。。");
		}else{
			System.out.println("猫还在。。。");
		}
	}
}

运行结果

[姓名:花花, 年龄:12, 品种:英国短毛猫]
[姓名:凡凡, 年龄:3, 品种:中华田园猫]
**********************************
添加重复数据后的宠物猫信息:
[姓名:花花, 年龄:12, 品种:英国短毛猫]
[姓名:凡凡, 年龄:3, 品种:中华田园猫]
**********************************
添加花花二代后的宠物猫信息:
[姓名:花花, 年龄:12, 品种:英国短毛猫]
[姓名:凡凡, 年龄:3, 品种:中华田园猫]
[姓名:花花二代, 年龄:2, 品种:英国短毛猫]
**********************************
花花找到了!
[姓名:花花, 年龄:12, 品种:英国短毛猫]
**********************************
通过名字查找花花信息
花花找到了
[姓名:花花, 年龄:12, 品种:英国短毛猫]
**********************************
**********************************
删除花花二代后的数据
[姓名:花花, 年龄:12, 品种:英国短毛猫]
**********************************
猫都不见了。。。
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值