天天看點

Java中Set集合的子類、HashSet、TreeSetHashSet集合LinkedHashSetTreeSet集合

HashSet集合

    存儲自定義對象

    HashSet集合的add方法去除重複元素依賴于HashCode()方法和equals()方法,存儲自定義對象的時候需要重寫這兩個方法。

String類型中底層已經重寫了equals()方法是以不用重寫。

package Set集合;

import java.util.HashSet;
import java.util.Set;

class Student {
	private String name;
	private int age;
	public Student() {
		super();
	}
	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;
	}
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	// HashSet集合的add方法依賴于HashCode()方法和equals()方法
	// 存儲自定義對象的時候需要重寫這兩個方法
	// String類型中底層已經重寫了equals()方法是以不用重寫
	@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;
		Student other = (Student) 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;
	}
	@Override
	public String toString() {
		return "學生 [姓名=" + name + ", 年齡=" + age + "]";
	}
	
}

public class SetTest {

	public static void main(String[] args) {
		Set<Student> s = new HashSet<Student>();
		//建立學生類對象
		Student s1 = new Student("張三", 21);
		Student s2 = new Student("張三", 21);
		//同名年齡不同屬于兩個人
		Student s3 = new Student("張三", 25);
		Student s4 = new Student("李四", 22);
		Student s5 = new Student("王五", 22);
		Student s6 = new Student("王五", 22);
		Student s7 = new Student("王五", 22);
		//添加到集合中
		s.add(s1);
		s.add(s2);
		s.add(s3);
		s.add(s4);
		s.add(s5);
		s.add(s6);
		s.add(s7);
		//周遊
		for (Student stu : s) {
			System.out.println(stu.toString());
		}
	}

}
/**
學生 [姓名=李四, 年齡=22]
學生 [姓名=張三, 年齡=25]
學生 [姓名=王五, 年齡=22]
學生 [姓名=張三, 年齡=21]
 */
           

可以發現輸出結果中除了排除了相同的實體外,順序也變化了。

LinkedHashSet

HashSet的子類,在HashSet的基礎上保證了元素的有序性。

  • LinkedHashSet底層是一種連結清單和哈希表組成
  • 可以保證元素的唯一性,是由哈希表決定的(hashCode()和equals())
  • 可以保證元素的疊代順序一緻(有序),存儲和取出一緻,是由連結清單決定
import java.util.LinkedHashSet;
import java.util.Set;

class Student {
	private String name;
	private int age;
	public Student() {
		super();
	}
	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;
	}
	public Student(String name, int age) {
		super();
		this.name = name;
		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;
		Student other = (Student) 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;
	}
	@Override
	public String toString() {
		return "學生 [姓名=" + name + ", 年齡=" + age + "]";
	}
	
}

public class SetTest {
	public static void main(String[] args) {
		//使用LinkedHashSet保證有序性
		Set<Student> s = new LinkedHashSet<Student>();
		//建立學生類對象
		Student s1 = new Student("張三", 21);
		Student s2 = new Student("張三", 21);
		//同名年齡不同屬于兩個人
		Student s3 = new Student("張三", 25);
		Student s4 = new Student("李四", 22);
		Student s5 = new Student("王五", 22);
		Student s6 = new Student("王五", 22);
		Student s7 = new Student("王五", 22);
		//添加到集合中
		s.add(s1);
		s.add(s2);
		s.add(s3);
		s.add(s4);
		s.add(s5);
		s.add(s6);
		s.add(s7);
		//周遊
		for (Student stu : s) {
			System.out.println(stu.toString());
		}
	}
}
/**
學生 [姓名=張三, 年齡=21]
學生 [姓名=張三, 年齡=25]
學生 [姓名=李四, 年齡=22]
學生 [姓名=王五, 年齡=22]
 */
           

可以看到使用LinkedHashSet集合存儲不光可以去除重複元素還保證了和添加時的順序一緻。

TreeSet集合

是通過自然順序對集合中的元素排序,在Set集合元素的唯一性的前提下對元素進行排序。

    TreeSet集合依賴于TreeMap紅黑樹結構實作,将存儲進集合的第一個元素作為根節點,以後每存儲一個元素都要依次和樹結構每一層的元素進行比較,以此來實作元素的排序。

import java.util.TreeSet;

public class TreeSetTese {
	public static void main(String[] args) {
		TreeSet<Integer> tr = new TreeSet<Integer>();
		tr.add(11);
		tr.add(5);
		tr.add(1);
		tr.add(8);
		tr.add(3);
		tr.add(9);
		tr.add(10);
		for (Integer inte : tr) {
			System.out.print(inte + ",");// 1,3,5,8,9,10,11,
		}
	}
}
           

    TreeSet集合存儲自定義對象

    TrssSet集合底層依賴于compareTo方法來比較元素,傳回值為0的時候判定元素重複。當存儲自定義類的時候自定義類需要實作Comparable接口中的compareTo方法來給TrssSet集合提供比較對象的規則。

import java.util.TreeSet;

class Student implements Comparable<Student> {
	// 自定義對象類需要實作Comparable接口重寫compareTo方法
	private String name;
	private int 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;
	}

	public Student() {
		super();
	}

	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	// TreeSet排序必須按照一個規則,存儲自定義對象的時候需要重寫compareTo方法
	@Override
	public int compareTo(Student o) {
		// 按年齡排序學生
		int num = this.age - o.age;
		// 為負數則說明目前對象比要比較的o對象小
		// 為正數則說明目前對象比要比較的o對象大
		// 為0則說明年齡相同,則按名字排序
		int num2 = num == 0 ? this.name.compareTo(o.name) : num;
		// 如果均為0說明兩個元素相同,則舍去重複元素
		return num2;
	}

	@Override
	public String toString() {
		return "姓名:" + name + "\t年齡:" + age;
	}

}

public class TreeSetTese {
	public static void main(String[] args) {
		TreeSet<Student> tr = new TreeSet<Student>();
		Student s1 = new Student("zhangsan", 21);
		Student s2 = new Student("lishi", 20);
		Student s3 = new Student("zhangsan", 21);
		Student s4 = new Student("wangwu", 20);
		Student s5 = new Student("zhaoliu", 22);
		Student s6 = new Student("zhaoliu", 25);
		Student s7 = new Student("zhaoliu", 25);
		tr.add(s1);
		tr.add(s2);
		tr.add(s3);
		tr.add(s4);
		tr.add(s5);
		tr.add(s6);
		tr.add(s7);
		for (Student stu : tr) {
			System.out.println(stu);
		}
	}
}
/**
姓名:lishi	年齡:20
姓名:wangwu	年齡:20
姓名:zhangsan	年齡:21
姓名:zhaoliu	年齡:22
姓名:zhaoliu	年齡:25
 */
           

    匿名内部類實作方式

實際開發中多使用匿名内部類的方式去重寫compareTo

實作一個按姓名長度排序,長度一樣按年齡排序:

import java.util.Comparator;
import java.util.TreeSet;

class Student{
	private String name;
	private int 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;
	}

	public Student() {
		super();
	}

	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	@Override
	public String toString() {
		return "姓名:" + name + "\t年齡:" + age;
	}

}

public class TreeSetTese {
	public static void main(String[] args) {
		TreeSet<Student> tr = new TreeSet<Student>(new Comparator<Student>() {
			//匿名内部類
			@Override
			public int compare(Student s1, Student s2) {
				//s1相當于目前元素
				//s2相當于比較的元素
				//按長度比較
				int num = s1.getName().length()-s2.getName().length();
				//長度一樣按年齡比較
				int num2=num==0?s1.getAge()-s2.getAge() :num;
				return num2;
			}
			
		});
		Student s1 = new Student("zhangsan", 21);
		Student s2 = new Student("lishi", 20);
		Student s3 = new Student("zhangsan", 21);//重複元素會被舍棄
		Student s4 = new Student("wangwu", 20);
		Student s5 = new Student("zhaoliu", 22);
		Student s6 = new Student("zhaoliu", 25);
		Student s7 = new Student("zhaoliu", 26);
		Student s8 = new Student("lishi", 21);
		Student s9 = new Student("zhangsan", 22);
		tr.add(s1);
		tr.add(s2);
		tr.add(s3);
		tr.add(s4);
		tr.add(s5);
		tr.add(s6);
		tr.add(s7);
		tr.add(s8);
		tr.add(s9);
		for (Student stu : tr) {
			System.out.println(stu);
		}
	}
}
/**
姓名:lishi	年齡:20
姓名:lishi	年齡:21
姓名:wangwu	年齡:20
姓名:zhaoliu	年齡:22
姓名:zhaoliu	年齡:25
姓名:zhaoliu	年齡:26
姓名:zhangsan	年齡:21
姓名:zhangsan	年齡:22
 */