JAVA_JCF(Java Collection Framework)学习笔记(三)

本文深入探讨Java集合框架中Set接口的实现,包括HashSet和TreeSet的特点及应用。详细解析了HashSet如何利用hashCode和equals方法保证元素唯一性,以及TreeSet的两种排序方式:自然排序和定制排序。

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

Set接口

Collection
|-------List:元素是有序的,元素可以重复,因为该集合体系有索引。
     |------ArrayList:底层的数组结构使用的是数组结构。特点:查询速度快,但是增删稍慢,线程不同步。
     |------LinkedList:底层使用的链表结构。特点:增删速度快,查询慢。
     |------Vector:底层是数组结构,线程同步,被ArrayList替代了。
|-------Set:元素是无序的(存入和取出的顺序不一定一致),元素不可以重复。
     |-------HashSet:底层数据结构是哈希表.线程是非同步的
保证元素唯一性的原理,判断元素的hashCode值是否相同
如果相同还会继续判断元素的equals方法,是否为true
     |-------TreeSet:可以对Set集合中的元素进行排序
底层数据结构是二叉树
保证元素唯一性的依据:compareTo方法return 0

HashSet

底层数据结构使用哈希表

HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals方法。
如果元素的hashCode值相同,才会判断equals是否为true。
如果元素的hashCode值不同,不会调用equals。



Person类:
public class Person {

	private String name;
	private String age;

	public Person() {
	}

	public Person(String name, String age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

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

	public String getAge() {
		return age;
	}

	public void setAge(String age) {
		this.age = age;
	}

	@Override
	public boolean equals(Object obj) {

		System.out.println(this.name + "...equals");
		
		if (!(obj instanceof Person)) {
			return false;
		}
		Person person = (Person) obj;
		return this.name.equals(person.getName());
	}
	
	@Override
	public int hashCode() {
		System.out.println(this.name + "...hash");
		return this.name.hashCode();
	}
}
重写Person的hashCode方法和equals方法,观察使用HashSet添加person对象调用hashCode方法和equals方法。

	@Test
	public void testHashSet1() {

		HashSet<Person> persons = new HashSet<Person>();
		persons.add(new Person("lisi", "23"));
		persons.add(new Person("zhangsan", "24"));
		persons.add(new Person("wangwu", "25"));
		//===============输出结果===============//
//		lisi...hash
//		zhangsan...hash
//		wangwu...hash
	}
只调用hashCode方法
@Test
	public void testHashSet1() {

		HashSet<Person> persons = new HashSet<Person>();
		persons.add(new Person("lisi", "23"));
		persons.add(new Person("wangwu", "25"));
		persons.add(new Person("zhangsan", "24"));
		persons.add(new Person("wangwu", "26"));
		//===============输出结果===============//
//		lisi...hash
//		wangwu...hash
//		zhangsan...hash
//		wangwu...hash
//		wangwu...equals
	}
当第四次添加name为wangwu的person对象时,由于hashset容器中已经存在name为wangwu的person对象,所以会继续调用person对象的equals方法。

注意:对于HashSet容器中判断元素是否存在,以及删除等操作,依赖的方法是元素的hashCode和equals方法。因为需要使用hash值在Hash表中查找元素,如果查出不仅仅是一个元素,则继续调用元素的equals方法,进行判断是否是同一个元素。

TreeSet


TreeSet排序的第一种方式,让元素自身具备比较性。元素类需要实现Comparable接口,覆盖compareTo方法,这种方式也成为了元素的自然排序,或者叫做默认排序。
TreeSet排序的第二种方式,当元素自身不具备比较性时,或者具备的比较性不是所需要的,这是需要让集合自身具备比较性,即集合初始化就有了比较性。

第一种排序方式:
Person类:
public class Person implements Comparable<Person> {

	private String name;
	private String age;

	public Person() {
	}

	public Person(String name, String age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

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

	public String getAge() {
		return age;
	}

	public void setAge(String age) {
		this.age = age;
	}

	@Override
	public int compareTo(Person o) {
		
		int num  = this.name.compareTo(o.name);
		if (num == 0) {
			num = new Integer(this.age).compareTo(new Integer(o.age));
		}
		return num;
	}
	
	@Override
	public String toString() {
		return this.name + "..." + this.age;
	}
}
测试代码:
@Test
	public void testTreeSet() {

		TreeSet<Person> set = new TreeSet<Person>();
		set.add(new Person("java001", "05"));
		set.add(new Person("java023", "08"));
		set.add(new Person("java003", "04"));
		set.add(new Person("java034", "03"));
		set.add(new Person("java034", "09"));
		
		Iterator<Person> iterator = set.iterator();
		while(iterator.hasNext()){
			System.out.println(iterator.next());
		}

	}
第二种排序:
package cn.wangyu.collection;

public class Person implements Comparable<Person> {

	private String name;
	private String age;

	public Person() {
	}

	public Person(String name, String age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

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

	public String getAge() {
		return age;
	}

	public void setAge(String age) {
		this.age = age;
	}

	@Override
	public int compareTo(Person o) {
		
		int num  = this.name.compareTo(o.name);
		if (num == 0) {
			num = new Integer(this.age).compareTo(new Integer(o.age));
		}
		return num;
	}
	
	@Override
	public String toString() {
		return this.name + "..." + this.age;
	}
}
测试类:
@Test
	public void testTreeSet() {

		TreeSet<Person> set = new TreeSet<Person>(new Comparator<Person>() {

			@Override
			public int compare(Person o1, Person o2) {
				int num = new Integer(o1.getName().length()).compareTo(new Integer(o2.getName().length()));
				if (num==0) {
					num = o1.getName().compareTo(o2.getName());
				}
				return num;
			}
			
		});
		set.add(new Person("java000001", "05"));
		set.add(new Person("java0023", "08"));
		set.add(new Person("ja3", "04"));
		set.add(new Person("ja034", "03"));
		set.add(new Person("java034", "09"));
		
		Iterator<Person> iterator = set.iterator();
		while(iterator.hasNext()){
			System.out.println(iterator.next());
		}

	}
当元素自身不具备比较性,或者具备的比较性不是所需要的。这是需要让容器具备比较性。
定义了比较器,将比较对象作为参数传递给TreeSet集合的构造函数

当两种排序都存在的情况下,以比较器为主,定义一个类,实现Comparator接口,覆盖compare方法。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值