Set集合

Set集合

Set集合概述

  • Set集合与Collection集合中的方法一模一样

HashSet

一.概述

  • HashSet实现Set接口,由哈希表支持。它不保证set的迭代顺序,特别是它不保证该顺序恒久不变。此类允许使用null

二.HashSet存储字符串遍历


import java.util.HashSet;

public class Demo1_HashSet {
	public static void main(String[] args) {
		HashSet<String> hs = new HashSet<>();          //创建HashSet对象
		boolean b1 = hs.add("a");
		boolean b2 = hs.add("a");                      //当向set集合中存储重复元素的时候返回false
		hs.add("b"); 
		hs.add("c"); 
		hs.add("d"); 
		System.out.println(hs);                        //HashSet的继承体系中有重写方法toString
		System.out.println(b1);//true
		System.out.println(b2);//false    
		
		for (String string : hs) {
			System.out.println(string);                //只要能用迭代器迭代的就可以用增强for循环
			//a  b  c  d
		}
	}
}

三.HashSet存储自定义对象保证元素唯一性

一.HashSet原理

1.我们使用Set集合都是需要去除重复元素的,如果在存储的时候逐个进行equals()比较,效率较低,哈希算法提高了去重复的效率,降低了equals()方法的使用次数

2.当HashSet调用add()方法存储对象的时候,先调用对象的hashCode()方法得到一个哈希值,然后在集合中查找是否有哈希值相同的对象

  • 如果没有哈希值相同的对象就直接存入集合
  • 如果有哈希值相同的对象,就和哈希值相同的对象进行equals()比较,比较结果为false就存入,true则不存

二.将自定义类的对象存入HashSet去重复

  • 类中必须要重写hashCode()和equals方法
  • hashCode():属性相同的对象返回值必须相同,属性不同的返回值尽量不同(提高效率)
  • equals():属性相同返回true,不同返回false,返回false的时候存储

案例演示


public class Person {
	private String name;
	private int age;
		
	public Person() {
		super();	
	}

	public Person(String name, int age) {
		super();
		this.name = name;
		this.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 String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
    /*
    代码优化:为了减少调用equals方法比较,优化hashCode代码写法
	最终版就是自动生成的
    */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)                    //调用的对象和传入的对象是同一个对象
			return true;                    //直接返回true
		if (obj == null)	                //传入对象为null
			return false; 				    //返回false
		if (getClass() != obj.getClass())   //判断两个字节码文件是否为同一个字节码文件
			return false;				    //如果不是直接返回false
		Person other = (Person)obj;         //向下转型
		if (age != other.age)  				//如果调用对象的年龄不等于传入对象的年龄
			return false; 				    //返回false
		if (name == null) {                 //如果调用对象的姓名为null
			if (other.name != null)         //传入对象的姓名也为null
				return false;               //返回false
		} else if (!name.equals(other.name))//调用对象的姓名不等于传入对象的姓名
			return false;                   //返回false
		return true;     					//如果相等返回true
		/*System.out.println("执行了吗");
		Person p = (Person)obj;
		return this.name.equals(p.name) && this.age == p.age;
		*/
	}
      /*
	   为什么是31?
	   1、31是质数,质数是能被1和自己本身整除的数、
	   2、31这个数既不大也不小
	   3、31这个数好算,2的五次方-1,2向左移动五位
	   */
	@Override
	public int hashCode() {
		//return 10; //返回常量码值,每个对象码值都相同,需要频繁调用equals方法,速度慢
		//为了减少equals方法的使用,应该都返回不同的码值,所以就有了hashCode方法
		/*
		final int NUM = 38;
		return name.hashCode() * NUM + age;//根据属性返回不同的码值,降低重复几率,减少equals方法的调用
		*/
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	
}

import java.util.HashSet;
import com.heima.bean.Person;

public class Demo1_HashSet {
	public static void main(String[] args) {
		HashSet<Person> hs = new HashSet<>();
		hs.add(new Person("张三",23));
		hs.add(new Person("张三",23));
		hs.add(new Person("李四",23));
		hs.add(new Person("李四",23));
		hs.add(new Person("李四",23));
		hs.add(new Person("李四",23));
		
		System.out.println(hs);
	}
}

LinkedHashSet

  • 底层是由链表实现的,是Set集合中唯一一个能保证怎么存就怎么取得集合对象
  • 因为是HashSet的子类,所以也是保证元素唯一的,与HashSet的原理一样

案例演示


import java.util.LinkedHashSet;

public class Demo2_LinkedHashSet {
	public static void main(String[] args) {
		LinkedHashSet<String> lhs = new LinkedHashSet<>();
		lhs.add("a");
		lhs.add("a");
		lhs.add("a");
		lhs.add("b");
		lhs.add("c");
		lhs.add("d");
		
		System.out.println(lhs);
	}
}

TreeSet

一.TreeSet集合概述

  • TreeSet集合是用来对元素进行排序的,同样他也可以保证元素的唯一
import java.util.TreeSet;

public class Demo3_TreeSet {
	public static void main(String[] args) {
		TreeSet<Integer> ts = new TreeSet<>();
		ts.add(3);
		ts.add(1);
		ts.add(1);
		ts.add(2);
		ts.add(2);
		ts.add(3);
		ts.add(3);
		
		System.out.println(ts);//123
	}
}

二.TreeSet集合保证元素唯一性和自然排序的原理

  • 当compareTo方法返回0时集合只有一个元素
  • 当compareTo方法返回正数时集合怎么存就怎么取
  • 当compareTo方法返回负数时集合会倒序存储

案例演示

public class Person implements Comparable<Person>{//实现Comparable接口,才能重写compareTo方法
	private String name;
	private int age;
		
	public Person() {
		super();
		
	}

	public Person(String name, int age) {
		super();
		this.name = name;
		this.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 String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
    /*//按年龄排序
	@Override
	public int compareTo(Person o) {
		int num = this.age - o.age;
		return num == 0 ? this.name.compareTo(o.name) : num;
	}*/
	
	/*//按姓名排序,其实是Unicode码表
	@Override
	public int compareTo(Person o) {
		int num  = this.name.compareTo(o.name);     //姓名是主要条件
		return num == 0 ? this.age - o.age : num;   //年龄是次要条件
	}*/
	
	//按姓名长度排序
	@Override
	public int compareTo(Person o) {
		int length = this.name.length() - o.name.length();
		int num = length == 0 ? this.name.compareTo(o.name) : length;
		return num == 0 ? this.age - o.age : num;
	}
}

import java.util.TreeSet;
import com.heima.bean.Person;

public class Demo3_TreeSet {
	public static void main(String[] args) {
		TreeSet<Person> ts = new TreeSet<>();
		ts.add(new Person("张三",23));
		ts.add(new Person("李四",13));
		ts.add(new Person("王五",43));
		ts.add(new Person("赵六",33));
		
		System.out.println(ts);
	}
}	

三.比较器排序

  • 实现Comparator接口,接口中有compare方法,重写此方法进行比较
  • TreeSet构造方法传入Comparator的子类对象
class CompareBylen implements Comparator<String> {//实现Comparator接口,接口中有compare方法,重写此方法
	@Override
	public int compare(String s1, String s2) {
		int num = s1.length() - s2.length();      //长度是主要条件
		return num == 0 ? s1.compareTo(s2) : num; //内容是次要条件
	}
}

import java.util.Comparator;
import java.util.TreeSet;
import com.heima.bean.Person;

public class Demo3_TreeSet {
	public static void main(String[] args) {
		//demo1();
		//demo2();
		//demo3();
		//demo4();
		//需求:把字符串按照长度排序
		TreeSet<String> ts = new TreeSet<>(new CompareBylen());//构造方法//Comparator c = new CompareByLen();
		ts.add("aaaaaaaa");
		ts.add("z");
		ts.add("wc");
		ts.add("nba");
		ts.add("cba");
		
		System.out.println(ts);//[z, wc, cba, nba, aaaaaaaa]
	}
}

四.TreeSet原理

A.TreeSet是用来排序的,可以指定一个顺序,对象存入之后会按照指定的顺序排序
B.使用方法

a: 自然顺序(Comparable)

  • TreeSet类的add()方法会把存入的对象提升为Comparable类型
  • 调用对象的compareTo()方法和集合中的对象比较
  • 根据compareTo()方法返回的结果进行储存

b: 比较器顺序(Comparator)

  • 创建TreeSet的时候可以指定一个Comparator
  • 如果传入了Comparator的子类对象,那么TreeSet就会按照比较器中的顺序排序
  • add()方法内部会自动调用Comparator接口中的compare()方法排序
  • 调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数

c: 两种方法的区别

  • TreeSet构造函数什么都不传,默认按照类中的Comparable的顺序(没有就报错ClassCastException)
  • TreeSet如果传入Comparator,就优先按照Comparator
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值