Java 集合操作之Set接口

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_18948359/article/details/87742317

简述

Set 集合与 Collection 集合类似,但是它没有提供任何额外的方法。所有可以说 Set 其实就是一个 Collection,只不过其行为不同。Set 不允许包含相同的元素,如果试图把两个相同元素加入到同一个 Set 集合中,则添加操作失败,add() 方法会返回 false,并且不会增加新元素。

Set 接口下面有两个常用的子类:HashSet、TreeSet。

HashSet

HashSet 是按照 Hash 算法来存储其中的元素,因此具备有很好的存取和查找性能。

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

public class SetTest {

	public static void main(String[] args) {
		Set<String> all = new HashSet<>();
		all.add("Hello");
		all.add("Java");
		all.add("Hello");// 重复数据
		all.add("World");
		all.add(null);	// 添加一个 null 元素
		// HashSet属于无需排列
		System.out.println(all);	// [null, Java, Hello, World]
	}
}

通过代码输出,我们可以看到 HashSet 的几个特点:

  • 不能保证元素的排列顺序,顺序可能发生变化
  • 可以添加 null 的元素

另外:HashSet 不是同步的,如果多个线程同时访问一个 HashSet,如果有两个或者两个以上的线程同时修改 HashSet 集合时,必须通过代码来保证同步。

TreeSet

希望所有的内容可以自动进行排序操作,则可以使用Set的第二个子类 TreeSet。

import java.util.Set;
import java.util.TreeSet;

public class SetTest {

	public static void main(String[] args) {
		Set<String> all = new TreeSet<>();
		all.add("Hello");
		all.add("Java");
		all.add("Hello");// 重复数据
		all.add("World");
		// 不能添加 null 元素,添加之后会报 java.lang.NullPointerException
		// all.add(null);	
		// HashSet属于无需排列
		System.out.println(all);	// [Hello, Java, World]
	}
}

通过输出可以看到:TreeSet 类是有序的,不能添加 null 元素。

关于数据排序的说明

通过自定义的类来进行数据的排序保存,在 Java 中如果想要对一组对象进行排序,需要使用 Comparable 比较器:

import java.util.Set;
import java.util.TreeSet;

class Book implements Comparable<Book>{
	String title;
	double price;
	
	Book(String title, double price) {
		this.title = title;
		this.price = price;
	}

	public String toString() {
		return "书名:" + this.title + ",价格为:" + this.price + "\n";
	}

	@Override
	// 覆写 compareTo 方法
	public int compareTo(Book o) {
		// 通过 价格排序
		if (this.price > o.price) {
			return 1;
		} else if (this.price < o.price) {
			return -1;
		} else {
			return 0;
			// 通过调用String 类的比较大小,可以正常输出
			// return this.title.compareTo(o.title);	
		}
	}
}

public class TestDemo {

	public static void main(String[] args) {
		
		// 使用 TreeSet 排序
		Set<Book> all = new TreeSet<>();
		
		all.add(new Book("Java从入门到精通", 88.6));
		all.add(new Book("Java从入门到精通", 88.6));// 完全相同
		all.add(new Book("JSP从入门到精通", 88.6));// 价格相同
		all.add(new Book("Oracle", 89.6));// 完全不同
		all.add(new Book("Android", 66.8));
		
		Object[] obj = all.toArray();
		for (int i = 0; i < obj.length; i++) {
			System.out.println(obj[i].toString());
		}
	}
}

输出结果为:

书名:Android,价格为:66.8

书名:Java从入门到精通,价格为:88.6

书名:Oracle,价格为:89.6

上面的输出中,少了new Book("JSP从入门到精通", 88.6)这对象; 发现 TreeSet 依靠的是 Comparable 接口中的 compareTo() 方法判断是否重复数据,所以价格重复数据不被保存。 当 compareTo() 方法返回值为 0 时,就会被 TreeSet 当做同一个对象进行处理。

关于重复元素的说明

Comparable 接口只能负责 TreeSet 子类进行重复元素的判断,它并不是真正的用于能够进行重复元素验证的操作。如果想要判断重复元素那么只能够依靠 Object 类中提供的方法:

  • boolean equals(Object obj):对两个对象惊喜比较,以便确认是否相同
  • int hashCode(): 返回该对象的哈希码,相同的对象必须返回相同的哈希码
    生成HashCode1
    生成HashCode2
import java.util.HashSet;
import java.util.Set;
 
class Book {
	private String title;
	private double price;
 
	public Book(String title, double price) {
		this.title = title;
		this.price = price;
	}
 
	@Override
	// 重写 Object 类中的 haseCode
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		long temp;
		temp = Double.doubleToLongBits(price);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		result = prime * result + ((title == null) ? 0 : title.hashCode());
		return result;
	}
 
	@Override
	// 重写 Object 中的 equals
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Book other = (Book) obj;
		if (Double.doubleToLongBits(price) != Double.doubleToLongBits(other.price))
			return false;
		if (title == null) {
			if (other.title != null)
				return false;
		} else if (!title.equals(other.title))
			return false;
		return true;
	}
 
	@Override
	public String toString() {
		return "书名:《" + this.title + "》,价格:" + this.price + "元。";
	}
}
 
public class TestDemo {
	public static void main(String[] args) {
		Set<Book> all = new HashSet<>();
		all.add(new Book("Java从入门到精通", 88.6));
		all.add(new Book("Java从入门到精通", 88.6));// 完全相同
		all.add(new Book("JSP从入门到精通", 88.6));// 价格相同
		all.add(new Book("Oracle", 89.6));// 完全不同
		all.add(new Book("Android", 66.8));
		Object[] obj = all.toArray();
		for (int i = 0; i < obj.length; i++) {
			System.out.println(obj[i]);
		}
	}
}

控制台输出:

书名:《JSP从入门到精通》,价格:88.6元。
书名:《Java从入门到精通》,价格:88.6元。
书名:《Oracle》,价格:89.6元。
书名:《Android》,价格:66.8元。

猜你喜欢

转载自blog.csdn.net/qq_18948359/article/details/87742317