Java语言学习总结 扩展篇 HashSet集合介绍及使用

HashSet

Set & HashSet

Set接口的特点

  1. 不允许存储重复的元素
  2. 没有索引,没有带索引的方法,也不能使用普通的for循环遍历,用迭代器遍历和增强for循环

HashSet接口的特点

  1. 也不允许存储重复的元素
  2. 没有索引,没有带索引的方法,也不能使用普通的for循环遍历
  3. 是一个无序的集合,存储元素和取出元素的顺序有可能不一致
  4. 底层是一个哈希表的结构(查询速度非常快)

实例代码:

import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
public class HashsetClass {

	public static void main(String[] args) {
		Set<Integer> set = new HashSet<>();
		//添加元素
		set.add(1);
		set.add(2);
		set.add(3);
		set.add(1);
		
		//迭代器遍历
		Iterator<Integer> it =set.iterator();
		while(it.hasNext()) {
			Integer n =it.next();
			System.out.println(n);  //1 2 3
			
		}
		System.out.println("======================");
		for(Integer i : set) {
			System.out.println(i);
		}
	}
}

哈希值

哈希值是一个十进制的整数,就是对象的逻辑地址值,是模拟出来得到的地址,并不是数据实际存储的物理地址。 在Object类有一个方法,可以获取对象的哈希值。
int hashCode() 返回该对象的哈希码值

import multiTest.Person;

public class HashCoedClass {

	public static void main(String[] args) {
		// 
		Person p1 = new Person();
		int h1 = p1.hashCode();
		System.out.println(h1);
		
		Person p2 = new Person();
		int h2 = p2.hashCode();
		System.out.println(h2);

		System.out.println("========================");
		System.out.println(p1);
		System.out.println(p2);
	}
}

输出结果:
在这里插入图片描述
可见对象的地址值就是哈希值

String类的哈希值, String重写了hashCode()方法。所以返回的哈希值是一样的
实例代码:

		String s1 = new String("abc");
		String s2 = new String("abc");
		String s3 = new String("abcd");
		String s4 = new String("abcd");
		String s5 = new String("abcf");
		String s6 = new String("abcg");
		System.out.println(s1.hashCode());
		System.out.println(s2.hashCode());
		System.out.println(s3.hashCode());
		System.out.println(s4.hashCode());
		System.out.println(s5.hashCode());
		System.out.println(s6.hashCode());
		System.out.println("童话".hashCode());
		System.out.println("神话".hashCode());
		System.out.println("重地".hashCode());
		System.out.println("通话".hashCode());

输出结果:
输出结果
可见相同的字符串对象哈希值是一样的。 不同的字符串有不同的哈希值。但是 “重地” , “通话” 的哈希值是一样的,是一个特例。

HashSet集合存储数据的结构(哈希表)

哈希表底层采用数组+链表实现,即使用链表处理冲突同一哈希值的链表都存储在一个链表里。但是当位于一一个链表中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。
哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为**红黑树,**这样大大减少了查找时间。
简单的来说,哈希表是由数组+链表+红黑树( JDK1.8增加了红黑树部分)实现的,如下图所示。
分析图:
分析
(图片摘自b站的 黑马Java基础+就业班+各种项目idea版本 课程)

Set集合存储元素不重复的原理

原理分析如图:
分析图
(图片摘自b站的 黑马Java基础+就业班+各种项目idea版本 课程)

HashSet存储自定义类型元素

向HashSet集合中存储自定义类型元素时,需要重写对象中的hashCode() 和equals()方法,才能够保证HashSet集合的元素不重复。比如存储(String, Integer,…, Student, Person…)这些自定义的数据类型时,就得重写方法。

实例代码:
新建一个Person类,代码如下:

public class Person {
	private String name;
	private int age;
	
	public Person() {
		
	}
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
}

测试类代码如下:

import java.util.HashSet;

public class HashCodeTestClass {

	public static void main(String[] args) {
		//创建HashSet集合存储Person
		HashSet<Person> set = new HashSet<>();
		Person p1 = new Person("小美女",18);
		Person p2 = new Person("小美女",18);
		Person p3 = new Person("小美女",19);
		set.add(p1);
		set.add(p2);
		set.add(p3);
		System.out.println(set);
			
	}
}

输出结果如下:
输出结果

发布了72 篇原创文章 · 获赞 3 · 访问量 6187

猜你喜欢

转载自blog.csdn.net/Ace_bb/article/details/104143835