JAVA 基础知识整理-13(集合类)Set, HashSet,LinkedHashSet,TreeSet

1. Set 类

一个不包含重复元素的 collection。更正式地说,set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学上的 set 抽象。简而言之,Set 中的元素不重复,且无序(不像List那样按照存储顺序。)

方法摘要
boolean add(E o)
如果 set 中尚未存在指定的元素,则添加此元素(可选操作)。
boolean addAll(Collection<? extends E> c)
如果 set 中没有指定 collection 中的所有元素,则将其添加到此 set 中(可选操作)。
void clear()
移除 set 中的所有元素(可选操作)。
boolean contains(Object o)
如果 set 包含指定的元素,则返回 true。
boolean containsAll(Collection<?> c)
如果此 set 包含指定 collection 的所有元素,则返回 true。
boolean equals(Object o)
比较指定对象与此 set 的相等性。
int hashCode()
返回 set 的哈希代码值。
boolean isEmpty()
如果 set 不包含元素,则返回 true。
Iterator iterator()
返回在此 set 中的元素上进行迭代的迭代器。
boolean remove(Object o)
如果 set 中存在指定的元素,则将其移除(可选操作)。
boolean removeAll(Collection<?> c)
移除 set 中那些包含在指定 collection 中的元素(可选操作)。
boolean retainAll(Collection<?> c)
仅保留 set 中那些包含在指定 collection 中的元素(可选操作)。
int size()
返回 set 中的元素数(其容量)。
Object[] toArray()
返回一个包含 set 中所有元素的数组。
T[]
toArray(T[] a)
返回一个包含 set 中所有元素的数组;返回数组的运行时类型是指定数组的类型。

2. HashSet

此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证集合的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。

方法:
boolean add(E o)
如果此集合中还不包含指定元素,则添加指定元素。
void clear()
从此集合中移除所有元素。
Object clone()
返回此 HashSet 实例的浅表复制:并没有克隆这些元素本身。
boolean contains(Object o)
Returns 如果此集合不包含指定元素,则返回 true。
boolean isEmpty()
如果此集合不包含任何元素,则返回 true。
Iterator iterator()
返回对此集合中元素进行迭代的迭代器。
boolean remove(Object o)
如果指定元素存在于此集合中,则将其移除。
int size()
返回此集合中的元素的数量(集合的容量)。

注:HashSet的底层排序基于hashCode()和equals方法。因此在对对象进行add添加操作之前如果该对象没有重写这两个方法那么要先重写hashCode()和equals方法。(如果默认使用Object的hasCode()那么其值一般是不相同的,也就是说,就算里面)。String,Integer等类已经重写了hashCode()和equals()方法。

HashSet<Integer> hs = new HashSet<>();
		hs.add(100);
		hs.add(100);
		hs.add(50);
		hs.add(20);
		hs.add(10);
		System.out.println(hs);
		
[50, 100, 20, 10]

HashSet的add方法实际是HashMap的put方法,以下是相关的源码(目前感觉理解的不是很透彻,有时间再仔细研究):

private static final Object PRESENT = new Object();

public HashSet() {
        map = new HashMap<>();
    }
public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
	
	
public HashMap() {
    this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
    }	

transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;	

public V put(K key, V value) {
	if (table == EMPTY_TABLE) {
		inflateTable(threshold);
	}
	if (key == null)
		return putForNullKey(value);
	int hash = hash(key);
	int i = indexFor(hash, table.length);
	for (Entry<K,V> e = table[i]; e != null; e = e.next) {
		Object k;
		if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
			V oldValue = e.value;
			e.value = value;
			e.recordAccess(this);
			return oldValue;
		}
	}

	modCount++;
	addEntry(hash, key, value, i);
	return null;
}

3. LinkedHashSet类

底层数据结构由哈希表和链表组成。
哈希表保证元素的唯一性。
链表保证元素有序。(存储和取出是一致的)

构造方法:

LinkedHashSet()
构造一个具有默认初始容量(16)和负载因子(0.75)的新的,空的链接散列集。
LinkedHashSet(Collection<? extends E> c)
构造与指定集合相同的元素的新的链接散列集。
LinkedHashSet(int initialCapacity)
构造一个具有指定初始容量和默认负载因子(0.75)的新的,空的链接散列集。
LinkedHashSet(int initialCapacity, float loadFactor)
构造具有指定的初始容量和负载因子的新的,空的链接散列集。

public class LinkedHashSetDemo {
	public static void main(String[] args) {
		LinkedHashSet<String> lhs = new LinkedHashSet<>();
		lhs.add("Hello");
		lhs.add("world");
		lhs.add("JAVA");
		lhs.add("JAVA");
		lhs.add("Heoo");
		lhs.add("Hello");
		for(String s:lhs){
			System.out.println(s);
		}
	}
}

4. TreeSet

1)使用元素的自然顺序对元素进行排序。
2)或者根据创建Set时提供的Comparator进行排序。
3)具体取决于使用的是哪一种构造方法。

注:TreeSet底层数据结构为红黑树(一种自平衡二叉树),以此来保证元素的排序和唯一性。

构造方法:

TreeSet()
构造一个新的空 set,该 set 按照元素的自然顺序排序。
TreeSet(Collection<? extends E> c)
构造一个新 set,包含指定 collection 中的元素,这个新 set 按照元素的自然顺序 排序。
TreeSet(Comparator<? super E> c)
构造一个新的空 set,该 set 根据指定的比较器进行排序。
TreeSet(SortedSet s)
构造一个新 set,该 set 所包含的元素与指定的已排序 set 包含的元素相同,并按照相同的顺序对元素进行排序。

方法:

boolean add(E o)
将指定的元素添加到 set(如果尚未存在于该 set 中)。
boolean addAll(Collection<? extends E> c)
将指定 collection 中的所有元素添加到此 set 中。
void clear()
移除 set 中的所有元素。
Object clone()
返回 TreeSet 实例的浅表复制(并不克隆元素自身)。
Comparator<? super E> comparator()
返回用于确定已排序 set 顺序的比较器,或者,如果此树 set 使用其元素的自然顺序,则返回 null。
boolean contains(Object o)
如果 set 包含指定的元素,则返回 true。
E first()
返回已排序 set 中当前的第一个(最小)元素。
SortedSet headSet(E toElement)
返回此 set 的部分视图,要求其元素严格小于 toElement。
boolean isEmpty()
如果 set 不包含元素,则返回 true。
Iterator iterator()
返回对此 set 中的元素进行迭代的迭代器。
E last()
返回已排序 set 中当前的最后一个(最大)元素。
boolean remove(Object o)
将指定的元素从 set 中移除(如果该元素存在于此 set 中)。
int size()
返回 set 中的元素个数(其容量)。
SortedSet subSet(E fromElement, E toElement)
返回此 set 的部分视图,其元素从 fromElement(包括)到 toElement(不包括)。
SortedSet tailSet(E fromElement)
返回 set 的部分视图,其元素大于或等于 fromElement。

案例1

public class TreeSetDemo {
	public static void main(String[] args) {
		TreeSet<String> ts = new TreeSet<String>();
		ts.add("a");
		ts.add("d");
		ts.add("b");
		ts.add("m");
		ts.add("c");
		
	for(String s:ts){
		System.out.println(s);
	}
	}
}

案例2
通过实现Comparable接口,并重写compareTo方法来实现
用treeSet添加对象并遍历:
注:如果对象是自己写的类创建的,那么首先要在创建类的时候实现Comparable的compareTo接口:
Student类

public class Student implements Comparable {
@Override
public int compareTo(Object o) {
	// TODO Auto-generated method stub
	Student s =(Student)o;
	int num = this.age - s.age;
	int num1 = num==0 ? this.name.hashCode()-s.name.hashCode():num;
	return num1;
	
}
//Student代码太长,只粘贴于本主题相关的内容
}

TreeSet<Student> tst = new TreeSet<Student>();
	Student s= new Student("Kathy",33);
	tst.add(s);
	tst.add(new Student("John",29));
	tst.add(new Student("Manny",35));
	tst.add(new Student("zhang",30));
	tst.add(new Student("zhang",30));
	tst.add(new Student("John",29));
	tst.add(new Student("zhang",24));
	tst.add(new Student("Manny",32));
	//按照年龄排序,年龄相同姓名不同的话按照姓名
	for(Student s1: tst){
		System.out.println(s1.getName()+"-----"+s1.getAge());
	}
	
	}	
OutPut:
zhang-----24
John-----29
zhang-----30
Manny-----32
Kathy-----33
Manny-----35

案例3
以匿名内部类的方式构建Comparator子类对象

TreeSet<Student> tst1= new TreeSet<Student>(new Comparator<Student>(){

		@Override
		public int compare(Student s1, Student s2) {
			int num1 = s1.getAge()-s2.getAge();			
			int num2 = num1==0 ? s1.getName().hashCode()-s2.getName().hashCode():num1;
			return num2;
		}		
	});
	//TreeSet(Comparator<? super E> c)
	Student s1 = new Student("Kathy",33);
	tst1.add(s1);
	tst1.add(new Student("John",29));
	tst1.add(new Student("Manny",29));
	tst1.add(new Student("zhang",30));
	tst1.add(new Student("zhang",31));
	tst1.add(new Student("John",29));
	tst1.add(new Student("zhang",24));
	tst1.add(new Student("Manny",32));
	tst1.add(new Student("Manny",24));
	System.out.println("=======================================");
	for(Student s2: tst1){
		System.out.println(s2.getName()+"-----"+s2.getAge());
	}
output:	
Manny-----24
zhang-----24
John-----29
Manny-----29
zhang-----30
zhang-----31
Manny-----32
Kathy-----33
发布了55 篇原创文章 · 获赞 0 · 访问量 2068

猜你喜欢

转载自blog.csdn.net/KathyLJQ/article/details/104892336