Java中hashset 的父类_Java HashSet类

本文详细介绍了Java中HashSet的工作原理,包括如何存储元素、确保元素唯一性及其实现方式。同时提供了多个示例来展示如何使用HashSet。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首页 > 基础教程 > 集合框架 > HashSet类

Java HashSet类

HashSet使用的是相当复杂的方式来存储元素的,使用HashSet能够最快的获取集合中的元素,效率非常高(以空间换时间)。它会根据hashcode和equals来庞端是否是同一个对象,如果hashcode一样,并且equals返回true,则是同一个对象,不能重复存放。

构造函数

HashSet()

构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75。

HashSet(Collection extends E> c)

构造一个包含指定 collection 中的元素的新 set。

HashSet(int initialCapacity)

构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和默认的加载因子(0.75)。

HashSet(int initialCapacity, float loadFactor)

构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和指定的加载因子。 放

方法

1.equals()方法

用来实现Set中元素的不重复性,如果不覆盖(override)equals()方法,默认使用父类Object的equals方法,则只是比较对象的引用是否相同。

2.hashCode()

hashCode()方法时为了实现HashSet和LinkedHashSet而实现的。只有知道对象的hash值,才能根据这个hash值确定 存放在散列表的槽的index。同样,如果不覆盖(override)hashCode()方法,默认使用父类Object的hashCode()方法。

3.toString()方法

toString()方法在打印对象时会调用。如果不覆盖(override)toString()方法,默认使用父类Object的。

4.compareTo()方法

用户类要实现Comparable接口。这个方法主要用于将对象存放在TreeSet()时保证顺序的。由于是接口,所以用户类必须要实现这个方法。

继承关系

|--HashSet 底层是由HashMap实现的,通过对象的hashCode方法与equals方法来保证插入元素的唯一性,无序(存储顺序和取出顺序不一致),。

|--LinkedHashSet 底层数据结构由哈希表和链表组成。哈希表保证元素的唯一性,链表保证元素有序。(存储和取出是一致)

实现原理

往Haset添加元素的时候,HashSet会先调用元素的hashCode方法得到元素的哈希值 ,然后通过元素 的哈希值经过移位等运算,就可以算出该元素在哈希表中的存储位置。见下面2种情况:

情况1: 如果算出元素存储的位置目前没有任何元素存储,那么该元素可以直接存储到该位置上。

情况2: 如果算出该元素的存储位置目前已经存在有其他的元素了,那么会调用该元素的equals方法与该位置的元素再比较一次,如果equals返回的是true,那么该元素与这个位置上的元素就视为重复元素,不允许添加,如果equals方法返回的是false,那么该元素运行 添加。

class Person {

int id;

String name;

public Person(int id, String name) {

super();

this.id = id;

this.name = name;

}

@Override public String toString() {

return "{ 编号:" + this.id + " 姓名:" + this.name + "}";

}

@Override public int hashCode() {

System.out.println("=======hashCode=====");

return this.id;

}

@Override public boolean equals(Object obj) {

System.out.println("======equals======");

Person p = (Person) obj;

return this.id == p.id;

}

}

public class Demo2 {

public static void main(String[] args) {

/*

HashSet set = new HashSet();

set.add("狗娃");

set.add("狗剩");

set.add("铁蛋");

System.out.println("集合的元素:"+ set);

*/

HashSet set = new HashSet();

set.add(new Person(110, "狗娃"));

set.add(new Person(220, "狗剩"));

set.add(new Person(330, "铁蛋"));

//在现实生活中只要编号一致就为同一个人.

System.out.println("添加成功吗?" + set.add(new Person(110, "狗娃")));

System.out.println("集合的元素:" + set);

}

}

运行结果:

=======hashCode=====

=======hashCode=====

=======hashCode=====

=======hashCode=====

======equals======

添加成功吗?false

集合的元素:[{ 编号:220 姓名:狗剩}, { 编号:110 姓名:狗娃}, { 编号:330 姓名:铁蛋}]

例子

public class HashSetReview {

public static void main(String[] args) {

test1();

test2();

test3();

}

/**

* 当添加的是String或基本数据类型(自动装箱)

*/

private static void test1() {

HashSet < String > hashSet = new HashSet < >();

hashSet.add("你好啊");

hashSet.add("很好");

hashSet.add("很不错");

hashSet.add("你好啊"); // 重复元素将不会被添加到set

for (String string: hashSet) {

System.out.println(string);

}

HashSet < Integer > integers = new HashSet < Integer > ();

integers.add(21);

integers.add(26);

integers.add(27);

integers.add(32);

integers.add(29);

integers.add(21);

for (Integer integer: integers) {

System.out.println(integer);

}

// output:

//      很不错

//      你好啊

//      很好

//      32

//      21

//      26

//      27

//      29

// 可见添加String类型或基本类型包装类时(他们重写了equals和hashCode方法),重复元素不会添加到集合中,且输出与添加时的顺序无关

}

/**

* 测试添加自定义对象 - 没有重写了equals和hashCode方法时(去Info类中注释掉重写的方法)

*/

private static void test2() {

HashSet < Info > infoHashSet = new HashSet < Info > ();

infoHashSet.add(new Info(0, "qqq"));

infoHashSet.add(new Info(1, "wew"));

infoHashSet.add(new Info(2, "ete"));

infoHashSet.add(new Info(0, "qqq")); //重复元素

for (Info info: infoHashSet) {

System.out.println(info);

}

//output :

//      Info [id=2, adress=ete]

//      Info [id=0, adress=qqq]

//      Info [id=1, adress=wew]

//      Info [id=0, adress=qqq]

// 可见,重复元素被添加到了HashSet

}

/**

* 测试添加自定义对象 - 重写了equals和hashCode方法时

*/

private static void test3() {

HashSet < Info > infoHashSet = new HashSet < Info > ();

infoHashSet.add(new Info(0, "qqq"));

infoHashSet.add(new Info(1, "wew"));

infoHashSet.add(new Info(2, "ete"));

infoHashSet.add(new Info(0, "qqq")); // Info重写了equals和hashCode方法,重复元素将不会再添加到set中

for (Info info: infoHashSet) {

System.out.println(info);

}

//output :

//      Info [id=2, adress=ete]

//      Info [id=0, adress=qqq]

//      Info [id=1, adress=wew]

//  对比test2,可见HashSet不会保证元素的有序性,对于自定义对象,要保证添加到HashSet集合的元素唯一性,需重写它的equals和hashCode方法

}

}

总结

(1)HashSet是Set接口的实现。HashSet按Hash算法来存储集合中的元素,具有很好的存取和查找性能。

(2)HashSet不是同步的,多个线程访问是需要通过代码保证同步

(3)HashSet集合元素值可以使null。

(4)HashSet不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也有可能发生变化。

(5)当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据该HashCode值决定该对象在HashSet中的存储位置。如果有两个元素通过equals()方法比较返回true,但它们的hashCode()方法返回值不相等,HashSet将会把它们存储在不同的位置,依然可以添加成功。即,HashSet集合判断两个元素相等的标准是两个对象通过equals()方法比较相等,并且两个对象的hashCode()方法返回值也相等。

版权声明:本文为JAVASCHOOL原创文章,未经本站允许不得转载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值