java编程基础总结——23.Set接口及其实现子类

一、Set接口

学习 Collection 接口时, Collection 中可以存放重复元素,也可以不存放重复元素,List中是可以存放重复元素的。那么不重复元素给哪里存放呢?那就是 Collection 接口中的 Set 集合中的元素就是不重复的。
Set: 不包含重复元素的集合,不保证顺序,(具体是否有序要看子类实现,有的是基于二叉树实现的就是有序的) 而且方法和 Collection 一致。 Set 集合取出元素的方式只有 一种:迭代器。
Set 集合有多个子类,这里我们介绍其中的 HashSet(哈希表) TreeSet(基于二叉树实现的,有序的) LinkedHashSet(链表结构的) 这三个集合。
Set 方法完全来自 Collection 接口。

  对应数据结构中的哈希表:无序、不重复的非线性结构 

set原码:

不能包含重复元素的的集合,通常情况,set包含单独的值(map是键值对)

二、.Set接口实现子类

1. HashSet

此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺
序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。 是一个存放链表的数组

1). 常见方法:

 add()、contains()

@Test
	void testSet01() {
		// HashSet 是java中的一个标准的哈希表
		Collection<Integer> nums = new HashSet<>();
		nums.add(123);
		nums.add(456);
		nums.add(789);
		nums.add(1);
		nums.add(13);
		nums.add(258);
        nums.add(10);
		System.out.println(nums);
	}

 和自己添加的值顺序不同,无序

无序不是随机,会用特定的hash算法算值,而不是随机

@Test
	void testSet01() {
		// HashSet 是java中的一个标准的哈希表
		Collection<Integer> nums = new HashSet<>();
		nums.add(123);
		nums.add(456);
		nums.add(789);
		nums.add(1);
		nums.add(13);
		nums.add(258);
		nums.add(10);
		// add方法会返回一个boolean,表示是否添加成功
		System.out.println(nums.add(31));
		// 添加失败,返回false,表示之前已经存在了这个值
		System.out.println(nums.add(31));
 
        //是否包含某个元素
		System.out.println(nums.contains(1));
		System.out.println(nums.contains(11));
		System.out.println(nums);
	}

 2). 哈希表遍历

注意:哈希表是无序的(没有下标),因此无法使用常规的循环,通过下标访问

(1)迭代器访问

@Test
	void testSet02() {
		// HashSet 是java中的一个标准的哈希表
		Collection<Integer> nums = new HashSet<>();
		nums.add(123);
		nums.add(456);
		nums.add(789);
		nums.add(1);
		nums.add(13);
		nums.add(258);
		nums.add(10);
		
        //迭代器访问
		Iterator<Integer> it = nums.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	
	}

(2)for循环加强进行遍历

for (Integer i : nums) {
        System.out.println(i);

(3)forEach进行遍历

nums.forEach((i) ->System.out.println(i));

2. TreeSet:

    这个set是使用二叉树(红黑树)实现的一个集合,因此该集合是有序的

1). 排序规律

(1). 字符串按accll码值排序

@Test
	void testSet03() {
		Set<String> ss = new TreeSet<>();
		
		// 有序的集合
		ss.add("apply");
		ss.add("huawei");
		ss.add("mi");
		ss.add("mm");
		ss.add("vivo");
		ss.add("OPPO");
		
		System.out.println(ss);
	}

 

(2). 数字按大小排序

@Test
	void testSet04() {
		Set<Integer> ss = new TreeSet<>();
		// 有序的集合
		ss.add(1);
		ss.add(2);
		ss.add(33);
		ss.add(333);
		ss.add(12);
		ss.add(102);
		ss.add(50);
		System.out.println(ss);
	}

(3).对象

先定义一个Person类

package com.openlab.day20.entity;

public class Person {

	private int id;
	private String name;
	private String nickname;
	private String gender;
	private int age;

	public int getId() {
		return id;
	}

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

	public String getName() {
		return name;
	}

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

	public String getNickname() {
		return nickname;
	}

	public void setNickname(String nickname) {
		this.nickname = nickname;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}

	public int getAge() {
		return age;
	}

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

	public Person() {
	}

	public Person(int id, String name, String nickname, String gender, int age) {
		super();
		this.id = id;
		this.name = name;
		this.nickname = nickname;
		this.gender = gender;
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + ", nickname=" + nickname + ", gender=" + gender + ", age=" + age
				+ "]";
	}

}
@Test
	void testSet06() {
		Set<Person> ss = new TreeSet<>();
		ss.add(new Person(1, "cc", "曹孟德", "男", 32));
		ss.add(new Person(2, "lb", "刘玄德", "男", 28));
		ss.add(new Person(3, "sq", "孙百万", "男", 18));
		ss.add(new Person(4, "zf", "张翼德", "男", 24));
		ss.add(new Person(5, "gy", "关云长", "男", 26));
		ss.add(new Person(6, "hhd", "夏侯惇", "男", 43));
		ss.add(new Person(7, "lb", "吕奉先", "男", 23));
		ss.add(new Person(8, "dc", "貂蝉", "男", 16));
		
		System.out.println(ss);
	}

 

 

jvm不知道Person类应该怎样排序

String和Integer在定义的时候已经指定了排序规则,而我们自己写的Person没有制定规则,是让jvm自动去完成,但是jvm也不知道

注意:在java中,如果对象需要比较,则必须让该类实现Comparable接口

String和Integer(包装类)都实现了此接口

 

 所以Person要想进行比较也需要实现Comparable接口

要求传递一个跟原对象进行比较

 Comparable接口有个泛型,要求传递过来一个东西跟原对象进行比较,我们传递Person,比较比较同一个对象,不是同一个对象比较没有意义

重写方法:

该方法返回一个int的值

若返回一个 >0 的数,按照正序排序

若返回一个 <0 的数,按照降序排序

若返回一个 =0 的数,不变

@Override

public int compareTo(Person o) {
        return 0;

}

package com.openlab.day20.entity;

public class Person implements Comparable<Person> {

	private int id;
	private String name;
	private String nickname;
	private String gender;
	private int age;

	public int getId() {
		return id;
	}

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

	public String getName() {
		return name;
	}

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

	public String getNickname() {
		return nickname;
	}

	public void setNickname(String nickname) {
		this.nickname = nickname;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}

	public int getAge() {
		return age;
	}

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

	public Person() {
	}

	public Person(int id, String name, String nickname, String gender, int age) {
		super();
		this.id = id;
		this.name = name;
		this.nickname = nickname;
		this.gender = gender;
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + ", nickname=" + nickname + ", gender=" + gender + ", age=" + age
				+ "]";
	}

	@Override
	public int compareTo(Person o) {
        // 指定需要排序的规则!!!

		// 指定规则:id的升序排列
//		return this.getId() - o.getId();
		
        // 指定规则:age的降序排列
		return o.getAge() - this.getAge(); 
	}

}

 return this.getId() - o.getId();

比较当前对象和下一个对象的id,如果大于零,相当于return 1,

代码相当于

int temp = this.getId() - o.getId();

if(temp > 0){

        return 1;

}else{

        return -1;

}

 

2). 去重

且TreeSet是有序的

HashSet就不是了

@Test
	void testSet05() {
		// 生成一个大小固定的list
		List<Integer> list = Arrays.asList(1,3,34,5,5,6,7,88,8,8,88,99);
		Set<Integer> ss = new TreeSet<>();
		Set<Integer> s = new HashSet<>();
		ss.addAll(list);
		System.out.println(ss);
		s.addAll(list);
		System.out.println(s);
	}

 

 Arrays.asList() 将不定长的数据以ArrayList的形式返回,返回的是一个固定大小的ArrayList(传了几个数据就是几个,不能再改变)

三、LinkedHashSet

具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。此实现与 HashSet 的不同之外在
于,后者维护着一个运行于所有条目的双重链接列表。
此类提供所有可选的 Set 操作,并且 允许 null 元素。
HashSet 一样,它可以为基本操作( add contains remove )提供稳定的性能,假
定哈希函数将元素正确地分布到存储段中。由于增加了维护链接列表的开支,其性能很可能会比
HashSet 稍逊一筹,不过,这一点例外: LinkedHashSet 迭代所需时间与 set 大小 成正比,而
与容量无关。 HashSet 迭代很可能支出较大,因为它所需迭代时间与其 容量 成正比。
此实现不是同步的。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值