04 深入了解Set 集合

一 :Set和List的区别

注意:有序指元素存储顺序和取出顺序

List: 有序(存储顺序和取出顺序一致),可重复。

Set: 无序(存储顺序和取出顺序不一致),唯一。

问题:为什么存储字符串的时候,字符串相同的内容只能存储一个呢?代码如下:

package it.set;

import java.util.HashSet;
/**
 * HaehSet字符串存储并遍历
 * 问题:为什么存储字符串的时候,字符串相同的内容只能存储一个呢?
 * 通过查看add的源码我们发现,这个方法的底层依赖HashCode()和equals()两个方法;
 * 步骤:
 *      首先比较哈希值
 *      如果相同,继续走,比较地址值或者equals();
 *      如果不同,就直接添加到集合中
 * 按照方法的步骤来说:
 *     先看HashCode()值是否相同,
 *     相同 :继续走equals()方法,
 *           返回true,说明元素重复,就不添加。
 *           返回false,说明元素不重复,就添加到集合中。
 *     不同:就直接把元素添加到集合中。
 *     如果类没有重写这两个方法,默认使用的是Obiect()的,一般来说不会相同。
 * 而String就重写了HashCode()和equals()方法,它就可以把内容相同的字符串去掉,只留下一个。
 */
public class HashSetTest {
	public static void main(String[] args) {
		//创建集合对象,
		HashSet<String> set = new HashSet<String>();
		//添加元素
		set.add("hello");
		set.add("world");
		set.add("java");
		set.add("world");

		//遍历元素
		for(String s:set){
			System.out.println(s);
		}
	}
	
}

二 Set集合及他的子类HashSet和TreeSet

A:HashSet 特点:不保证Set的迭代顺序,特别是他不保证该顺序恒久不变。

问题:HashSet如何保证元素唯一性?

底层数据结构是哈希表(元素是链表的数组)

哈希表依赖于HashCode()和equals()两个方法;

练习:存储自定义对象,并保证唯一性/如果两个对象成员变量值都相同,则为同一元素。代码如下:

package Set.HashSet;

import java.util.HashSet;
/**
 * 需求:存储自定义对象,并保证唯一性/如果两个对象成员变量值都相同,则为同一元素。
 * 
 * 如果不重写学生类中的方法,则默认使用的是Object类,这个时候,
 * 的哈希值是不会一样的,根本就不会继续判断,执行了添加操作。
 * 
 * 
 * 由于HashSet集合的底层是哈希表结构,
 * 而哈希表结构底层依赖HashCode()和equals()两个方法;
 * 如果你认为对象的成员变量值相同,即为同一个对象的话,你就应该重写这两个方法,
 * 如何重写呢?不用担心自动生成即可
 * 
 */
public class HashSetDome01 {
	public static void main(String[] args) {
		
		HashSet<StudentHashset> set = new HashSet<StudentHashset>();
		//首先定义对象
		StudentHashset s1 = new StudentHashset("唐僧",30);
		StudentHashset s2 = new StudentHashset("孙悟空",29);
		StudentHashset s3 = new StudentHashset("猪八戒",28);
		StudentHashset s4 = new StudentHashset("唐僧",30);
		StudentHashset s5 = new StudentHashset("沙和尚",27);
		StudentHashset s6 = new StudentHashset("唐僧",27);
		//添加元素
		set.add(s1);
		set.add(s2);
		set.add(s3);
		set.add(s4);
		set.add(s5);
		set.add(s6);

		//遍历元素
		for(StudentHashset s:set){
			System.out.println(s.getName()+"======"+s.getAge());
		}
	}
	
}

对应的学生类,需要重写HashCode()和equals()方法

package Set.HashSet;

public class StudentHashset {
	private String  name;
	private int  age;
	public StudentHashset(){
		
	}
	public StudentHashset(String name,int age){
		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 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;
		StudentHashset other = (StudentHashset) 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;
	}
	
}
B:TreeSet 特点:排序和唯一 ,能够让元素按照某种规则进行排序,1)自然排序 2)比较器排序(comparator接口)
第一 :自然排序(要想实现自然排序,必须实现Comparable<E>接口),代码如下:
package Set.TreeSet;

import java.util.TreeSet;
/****
 * TreeSet 存储自定义对象并保证排序和唯一
 * A: 你没有告诉我怎么排序?
 *        自然排序,安照年龄从小到大排序
 * B: 元素什么情况下算唯一,你也没告诉我?
 *        成员变量值都相同即为同一个元素
 */
public class TreeSetDome02 {
	public static void main(String[] args) {
		//创建集合对象
		TreeSet<StudentTreeset> ts = new TreeSet<StudentTreeset>(); 
		//创建元素
		StudentTreeset s1 = new  StudentTreeset("zhangxinxin",25);
		StudentTreeset s2 = new  StudentTreeset("lilibo",30);
		StudentTreeset s3 = new  StudentTreeset("zhangtao",19);
		StudentTreeset s4 = new  StudentTreeset("zhangxinxin",20);
		StudentTreeset s5 = new  StudentTreeset("lilibo",30);
		StudentTreeset s6 = new  StudentTreeset("guojiali",26);
		StudentTreeset s7 = new  StudentTreeset("aili",19);
        //添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);
        ts.add(s7); 
        
		
		for(StudentTreeset s:ts){
			System.out.println(s.getName()+"---"+s.getAge());
			
		}
		
	}

}

如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口

package Set.TreeSet;
/**
 * 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口。
 *
 */

public class StudentTreeset  implements Comparable<StudentTreeset>{
	private String  name;
	private int  age;
	public StudentTreeset(){
		
	}
	public StudentTreeset(String name,int age){
		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 int compareTo(StudentTreeset s) {
		//这里返回什么,其实应该根据我的排序规则来做
		//按照年龄排序,主要条件(添加那个对象,那个对象叫this,它要和其他元素进行比较)
		int num = this.age - s.age; 
//		return num;
		//次要条件 年龄相同的时候还要去看姓名是否相同
		//如果年龄和姓名都相同,才是同一个元素
	    int num2 = num == 0 ? this.name.compareTo(s.name) : num;  //如果年龄相同,继续比姓名,否则返回num年龄;
		return num2;
		
	}
	
	
}

第二:比较器排序(comparator接口)

package Set.TreeSet;

import java.util.Comparator;
import java.util.TreeSet;
/****
 * TreeSet 存储自定义对象并保证排序和唯一
 * 比较器排序,如果一个方法的参数是接口,那么真正要的接口的实现类对象
 */
public class TreeSetDome03 {

	public static void main(String[] args) {
		//创建集合对象
		//TreeSet<StudentTreeset> ts = new TreeSet<StudentTreeset>(); //自然排序
		//public TreeSet(Comparator comparator); //比较器排序 
		//TreeSet<StudentTreeset> ts = new TreeSet<StudentTreeset>(new MyComparator());
		TreeSet<StudentTreeset> ts = new TreeSet<StudentTreeset>(new  Comparator<StudentTreeset>(){
			@Override
			public int compare(StudentTreeset s1, StudentTreeset s2) {
				//姓名长度
				int num = s1.getName().length()-s2.getName().length();
				//姓名
				int num1 = num==0?s1.getName().compareTo(s2.getName()):num;
				//年龄
				int num2 = num1==0?s1.getAge()-s2.getAge():num1;
				return num2;
			}	
		});
		
		//创建元素
		StudentTreeset s1 = new  StudentTreeset("zhangxinxin",25);
		StudentTreeset s2 = new  StudentTreeset("lilibo",30);
		StudentTreeset s3 = new  StudentTreeset("zhangtao",19);
		StudentTreeset s4 = new  StudentTreeset("zhangxinxin",20);
		StudentTreeset s5 = new  StudentTreeset("lilibo",30);
		StudentTreeset s6 = new  StudentTreeset("guojiali",26);
		StudentTreeset s7 = new  StudentTreeset("aili",19);
        //添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);
        ts.add(s7); 
        
		
		for(StudentTreeset s:ts){
			System.out.println(s.getName()+"---"+s.getAge());
			
		}
		
	}

}

最后总结:TreeSet集合保证元素排序和唯一性原理

唯一性:是根据比较的返回值是不是0来决定

排序:

A:自然排序(元素具备比较性)

     让元素所属的类实现自然排序接口Comparable

B:比较器排序(集合具备比较性)

     让集合的构造方法接收一个比较器接口的子类对象Comparator



猜你喜欢

转载自blog.csdn.net/zhangxinxin1108/article/details/79514829