实现set接口的类有HashSet和TreeSet,HashSet底层的实现是hash表,TreeSet的实现是二叉树,它们不允许向集合中存放相同的数据元素,HashSet添加对象的原理是调用对象的hashcode方法,根据返回的值使用指定的算法映射到一个地址上面,看这个地址上有没有对象,没有的话,就添加到这个地址上,如果有的话,调用对象的equeals方法,看是否相同,如果和其他的对象相同,则不添加,如果不同再映射到其他的地址上。所以如果是添加自定义的数据类型,则要覆写equals方法和hashcode方法。hashset集合中内部元素的排列顺序就是根据这个hash值。

package zaojiahua;

public class Dog
{
	//私有成员变量
	private int age;
	private String name;

	//俩个构造函数
	Dog()
	{
		age = 0;
		name = "dog";
	}
	Dog(int age,String name)
	{
		this.age = age;
		this.name = name;
	}

	//覆写equals方法
	public boolean equals(Object obj)
	{
		//如果传入的就是同一个对象,即堆上的地址相同,则返回true
		if(this == obj)
			return true;

		//判断传入的对象是否为Dog的对象
		boolean ret = obj instanceof Dog;

		if(ret)
		{
			Dog d = (Dog)obj;
			if(d.age == this.age && d.name.equals(this.name))
			{
				return true;
			}
		}

		return false;
	}

	//覆写hashcode方法,返回散列码值,object中的hashCode方法返回的是对象的地址值
	public int hashCode()
	{
		//result应该是一个素数
		int result = 17;
		result = result*31+age;
		result = result*31+name.hashCode();
		return result;
	}
}
package zaojiahua;

import java.util.HashSet;
import zaojiahua.Dog;

public class Test
{
	public static void main(String args[])
	{
		HashSet<String> set = new HashSet<String>();
		set.add("aaa");
		set.add("bbb");
		//不允许添加相同的元素
		System.out.println(set.add("aaa")); //false

		HashSet<Dog> dog_set = new HashSet<Dog>();
		//添加引用数据类型需要覆写hashCode和equals方法
		Dog d1 = new Dog(20,"dog");
		Dog d2 = new Dog(20,"dog");
		dog_set.add(d1);
		System.out.println(dog_set.add(d2)); //false
	}
}

 接下来看看TreeSet如何使用,方法大致都是相同的,区别是TreeSet可以使用自定义的排序规则对传入的对象进行排序,自定义的数据类型可以实现comparable接口,覆写compareTo方法,或者定义一个比较器进行比较。这里有非常重要的一点需要注意,TreeSet判断俩个元素是否相等使用的就是比较函数,而不是hashcode和equals方法,本人在这里就犯了错误。误以为比较和判断是否相同调用的函数不同。

package zaojiahua;

public class Dog implements Comparable<Object>
{
	//私有成员变量
	private int age;
	public int getAge() {
		return age;
	}
	public String getName() {
		return name;
	}

	private String name;

	//俩个构造函数
	Dog()
	{
		age = 0;
		name = "dog";
	}
	Dog(int age,String name)
	{
		this.age = age;
		this.name = name;
	}

	//覆写equals方法
	public boolean equals(Object obj)
	{
		//如果传入的就是同一个对象,即堆上的地址相同,则返回true
		if(this == obj)
			return true;

		//判断传入的对象是否为Dog的对象
		boolean ret = obj instanceof Dog;

		if(ret)
		{
			Dog d = (Dog)obj;
			if(d.age == this.age && d.name.equals(this.name))
			{
				return true;
			}
		}

		return false;
	}

	//覆写hashcode方法,返回散列码值,object中的hashCode方法返回的是对象的地址值
	public int hashCode()
	{
		//result应该是一个素数
		int result = 17;
		result = result*31+age;
		result = result*31+name.hashCode();
		return result;
	}

	public String toString()
	{
		return age+":"+name;
	}

	//覆写compareTo方法
	public int compareTo(Object obj)
	{
		if(this == obj)
			return 1;

		boolean ret = obj instanceof Dog;
		if(ret)
		{
			Dog d = (Dog)obj;
			if(this.age != d.age)
				return this.age-d.age;
			else
				return this.name.compareTo(d.name);
		}
		else
		{
			throw new RuntimeException("不是dog的对象");
		}
	}
}
package zaojiahua;

//import java.util.HashSet;
import java.util.Comparator;
import java.util.TreeSet;
import zaojiahua.Dog;

public class Test
{
	public static void main(String args[])
	{
		TreeSet<String> set = new TreeSet<String>();
		set.add("aaa");
		set.add("bbc");
		set.add("bbb");
		//默认的排序方式是调用compareTo方法
		System.out.println(set);

		//当添加自定义的数据类型时,要想按照自己的方式排序,就需要继承comparable接口
		//覆写compareTo方法
		Dog dog1 = new Dog(19,"a");
		Dog dog2 = new Dog(19,"b");
		Dog dog3 = new Dog(18,"c");
		//TreeSet<Dog> dog_set = new TreeSet<Dog>();
		//采用以下的方式,传入一个自定义的比较器
		TreeSet<Dog> dog_set = new TreeSet<Dog>(new MyCompare());
		dog_set.add(dog1);
		dog_set.add(dog2);
		dog_set.add(dog3);
		//比较器的优先级大于元素本身比较的优先级
		System.out.println(dog_set);
	}
}

//自定义一个比较器,先按名字排序,再按照age排序
class MyCompare implements Comparator<Dog>
{
	public int compare(Dog d1,Dog d2)
	{
		int ret = d1.getName().compareTo(d2.getName());
		if(ret == 0)
			return d1.getAge()-d2.getAge();
		return ret;
	}
}

容器类Set 容器类Set