Set

Set接口中的方法和Collection一致

  • HashSet:内部是哈希表+ 红黑树数据结构;不同步
  • TreeSet:底层数据结构是红黑树(是一个自平衡的二叉树),可以对Set集合中的元素进行指定顺序的排序;不同步

HashSet

HashSet hs = new HashSet();
hs.add("hehe");
hs.add("haha");
hs.add("heihei");
hs.add("lala");

Iterator it = hs.iterator();
while(it.hasNext()) {
    System.out.println(it.next());  //无序
}

哈希表

  • 用hascode计算哈希值
  • 使用算法,比如y=k(x)等计算存储位置
  • 如果位置上有元素了就使用equals对比
  • 一样就覆盖,不一样就链表

自身的hashCode方法算出了hash值,从而来决定在哈希表中位置,可以覆盖,所以无序

//HashSet数据结构是哈希表,所以存储元素的时候使用元素的hashCode方法来确定位置,如果位置相同,再通过
//元素的equals来确定内容是否相同
HashSet hs = new HashSet();
hs.add(new Person("list1",21));
hs.add(new Person("list2",22));
hs.add(new Person("list3",23));
hs.add(new Person("list4",24));
hs.add(new Person("list1",21));

Iterator it = hs.iterator();
while(it.hasNext()) {
    Person p = (Person)it.next();
    System.out.println(p.getName()+"--"+p.getAge());
}
//Person
public class Person extends Object {
	private String name;
	private int age;
	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;
	}
	//覆盖hashCode和equals方法
	@Override
	public boolean equals(Object obj) {
		if(this == obj) {
			return true;
		}
		if(!(obj instanceof Person)) {
			throw new ClassCastException("类型错误!");
		}
		System.out.println(this+"..equals.."+obj);
		Person p = (Person)obj;
		return this.name.equals(p.name) && this.age == p.age;
	}
	@Override
	public int hashCode() {
		System.out.println(name+"|"+age+"...hashCode=" + (name.hashCode()+age*35));
		return name.hashCode()+age*35;
	}
}
HashSet hashSet = new HashSet();
	hashSet.add(new Person("zhangsan", 12));
	hashSet.add(new Person("lisi", 12));
	hashSet.add(new Person("zhangsan", 12));  //如果不重写hascode和equals,这会看作是不同对象
	System.out.println(hashSet); //[Person [name=zhangsan, age=12], Person [name=zhangsan, age=12], Person [name=lisi, age=12]]
}

从顶部注释来看,我们就可以归纳HashSet的要点了:

  • 实现Set接口
  • 不保证迭代顺序
  • 允许元素为null
  • 底层实际上是一个HashMap实例
  • 非同步
  • 初始容量非常影响迭代性能

我们知道Map是一个映射,有key有value,既然HashSet底层用的是HashMap,那么value在哪里呢???

可以很明显地看到,Set集合的底层就是Map,所以我都没有做太多的分析在上面,也没什么好分析的了。

HashSet源码分析

public class TestHashSet {
	/***
	 * HashSet底层源码分析
	 *  private transient HashMap<E,Object> map;
	 *   private static final Object PRESENT = new Object();
	 *  public HashSet() {
             map = new HashMap<>();//创建HashSet时,底层创建的是一个HashMap对象
     }
     public boolean add(E e) {
                     key-->e ,value-->PRESENT ,是一个Object类型的对象
                     map集合中的所有value都是统一的Object类型对象
        return map.put(e, PRESENT)==null;
        
     }
     public int size() {
        return map.size();
    }
    
     public boolean contains(Object o) {
        return map.containsKey(o);  //在map集合中判断key是否存在
    }
    public Iterator<E> iterator() {
          //获取map集合中所有的key的集合,再得到迭代器对象
        return map.keySet().iterator();
    }
    HashSet使用了HashMap的数据结构,
         底层都是哈希表 (顺序表+链表)
	 * @param args
	 */
	public static void main(String[] args) {
		//HashSet底层数组结构使用的是hash表  ,主结构数组, +链表
		//创建集合对象
		HashSet hs=new HashSet();
		hs.add("hello");
		hs.add("world");
		hs.add("java");
		System.out.println(hs.add("world"));
		System.out.println("集合中元素的个数:"+hs.size());
		System.out.println(hs);
		System.out.println(hs.contains("java")+"\t"+hs.contains("sql"));
		//使用迭代器遍历元素
		Iterator ite=hs.iterator();
		while(ite.hasNext()){
			System.out.println(ite.next());
		}
		
	}
}

LinkedHashSet

有序的HashSet

HashSet hs = new LinkedHashSet();
hs.add("hehe");
hs.add("haha");
hs.add("heihei");
hs.add("lala");

Iterator it = hs.iterator();
while(it.hasNext()) {
	System.out.println(it.next());  //无序
}

TreeSet

  • 和hashcode,equals没有关系
  • 可以对Set集合中的元素进行指定顺序的排序
  • 判断元素唯一性就是根据compareto的返回结果是不是0,是0就是相同的元素,就不会存,底层就是treemap

1. 让元素自身具备比较功能,需要实现Comparable接口,覆盖compareTo方法 TreeSet就是利用元素的比较方法来排序和排重

//Main
//以年龄排序
TreeSet ts = new TreeSet();
ts.add(new Person("zhangsan",28));
ts.add(new Person("zhangsan1",26));
ts.add(new Person("zhangsan2",22));
ts.add(new Person("zhangsan3",35));
ts.add(new Person("zhangsan3",28));


Iterator it = ts.iterator();
while(it.hasNext()) {
	Person p = (Person)it.next();
	System.out.println(p.getName()+"--"+p.getAge());
}
//zhangsan2--22
//zhangsan1--26
//zhangsan--28
//zhangsan3--28
//zhangsan3--35


//Person
public class Person extends Object implements Comparable {
	private String name;
	private int age;
	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;
	}
	//覆盖hashCode和equals方法
	@Override
	public boolean equals(Object obj) {
		if(this == obj) {
			return true;
		}
		if(!(obj instanceof Person)) {
			throw new ClassCastException("类型错误!");
		}
		System.out.println(this+"..equals.."+obj);
		Person p = (Person)obj;
		return this.name.equals(p.name) && this.age == p.age;
	}
	@Override
	public int hashCode() {
		System.out.println(name+"|"+age+"...hashCode=" + (name.hashCode()+age*35));
		return name.hashCode()+age*35;
	}
	@Override
	public int compareTo(Object o) {
		
		
		Person p =(Person)o;
		int temp = this.age-p.age;
		return temp==0?this.name.compareTo(p.name):temp;
		
//		if(this.age>p.age) {
//			return 1;
//		}
//		if(this.age<p.age) {
//			return -1;
//		}
//		if(this.age==p.age) {
//			this.name.compareTo(p.name);
//		}
		
	}
	
}

2. 有的时候元素自身不能具备比较,可以让集合自身具备比较器

让集合自身具备比较功能,定义一个类实现Comparator接口,覆盖Compare方法,
将该类对象作为参数传递给TreeSet构造函数

//main
TreeSet ts = new TreeSet(new ComparatorByName());
ts.add(new Person("zhangsan",28));
ts.add(new Person("zhangsan1",26));
ts.add(new Person("zhangsan2",22));
ts.add(new Person("zhangsan3",35));
ts.add(new Person("zhangsan3",28));


Iterator it = ts.iterator();
while(it.hasNext()) {
	Person p = (Person)it.next();
	System.out.println(p.getName()+"--"+p.getAge());
}
//ComparatorByName
public class ComparatorByName implements Comparator {

	@Override
	public int compare(Object o1, Object o2) {
		Person p1 = (Person)o1;
		Person p2 = (Person)o2;
		
		int temp = p1.getName().compareTo(p2.getName());
		
		return temp==0?p1.getAge()-p2.getAge() : temp;
	}

}

比较器固定返回1 return 1,可以实现有序TreeSet集合,放入和取出一样

字符串按长度排序

//main
TreeSet ts = new TreeSet(new ComparatorByLength());
ts.add("asfsa");
ts.add("asfsasadfadsgf");
ts.add("asfs14gsdaa");
ts.add("asfsas");



Iterator it = ts.iterator();
while(it.hasNext()) {
	System.out.println(it.next());
}
//ComparatorByLength
public class ComparatorByLength implements Comparator {

	@Override
	public int compare(Object o1, Object o2) {
		String s1 = (String)o1;
		String s2 = (String)o2;
		
		int temp = s1.length()-s2.length();
		
		return temp==0?s1.compareTo(s2) : temp;
	}
}

TreeSet源码分析


/** 
 * TreeSet的底层所使用的是TreeMap   -->红黑树
 * TreeSet JDK源码分析
 *  private transient NavigableMap<E,Object> m;  //一个接口,间接继承了Map
 *    private static final Object PRESENT = new Object();
 *  public TreeSet() {
        this(new TreeMap<E,Object>());  //创建了一个TreeMap的对象
    }
    //调用的本类中的带参构造方法
    TreeSet(NavigableMap<E,Object> m) {
        this.m = m;   //接口new 实现类
    }
     public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));  //调用了本类中的带参构造方法
    }
    添加方法
     public boolean add(E e) {
        return m.put(e, PRESENT)==null;  //传入的元素作为Map中的key,统一的值为Object类型的对象
    }
    public int size() {
        return m.size();
    }
    
    
 * @author Administrator
 *
 */
public class TestTreeSet {
	public static void main(String[] args) {
	
		//创建集合对象
		//TreeSet ts=new TreeSet();
		//Comparator comc=new ComCharactor();//创建外部比较器对象
		Comparator com=new ComCharactorAndAge();
		TreeSet ts=new TreeSet(com);
		//创建Person对象
		Person p1=new Person("marry", 20);
		Person p2=new Person("lili", 19);
		Person p3=new Person("jack", 20);
		Person p4=new Person("marry", 18);
		//添加到集合中
		ts.add(p1);
		ts.add(p2);
		ts.add(p3);
		ts.add(p4);
		System.out.println("集合中元素的个数:"+ts.size());
		System.out.println(ts);
	}
}


书籍推荐