本文主要內容:
(1)Set
(2)HashSet與TreeSet
集合:Collection(以value的形式存在)、Map(以key-value的形式存在)
- Set:無序、無重複
(1)無序:添加的順序與獲取的順序不一致(不是集合本身是否有序,Tree自然有序)
(2)無重複:添加的元素不能一致(如果出現重複的元素,只存第一個,不在存入)
(3)HashSet(HashMap—>數據存儲結構:哈希表:分爲開散列、閉散列)
這裏用的是開散列:數組+鏈表
(4)TreeSet(TreeMap—>數據存儲結構:搜索樹(中序有序))
(5)Set集合家族基本使用:(有標記的是HashSet的方法)
boolean=add(E e):如果指定的元素不存在,則將其指定的元素添加(!)
boolean=addAll(Collection<? extends E> c):將指定集合中的所有元素添加到此集合
boolean=contains(Object o):如果此集合包含指定的元素,則返回 true (!)
boolean=equals(Object o):將指定的對象與此集合進行比較以實現相等
int=hashCode():返回此集合的哈希碼值
boolean=isEmpty():如果此集合不包含元素,則返回 true (!)
Iterator=iterator():返回此集合中元素的迭代器(!)
boolean=remove(Object o):如果存在,則從該集合中刪除指定的元素(!)
int=size():返回此集合中的元素數(!)
Object[]=toArray():返回一個包含此集合中所有元素的數組
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
//Set源碼中的add方法,實際上用的是Map中的put方法,且將它當做key傳入
//所以set無重複,map中的key是無重複的
(6)Set集合無重複的特性:
HashSet:無重複的原則有兩個方法同時起作用:equals、hashCode,默認比較的是兩個對象的地址,若第二個對象地址與之前的一致,不在存入,如果想要改變其比較的規則,可以重寫上述的兩個方法。
HashSet<String> set = new HashSet<>();
set.add(new String("張三"));
set.add(new String("張三"));
set.add(new String("張三"));
System.out.println(set.size());//1
//在Set中無重複體現在equals方法與hashCode方法,又因爲String類的hashCode
//計算方式是計算每個字符的code碼乘以31在求和,所以相當於在重複
HashSet<Person> pSet = new HashSet<>();
pSet.add(new Person("李四"));
pSet.add(new Person("李四"));
pSet.add(new Person("李四"));
System.out.println(pSet.size());//3
//Person類的hashCode方法是繼承於Object類中的方法,Object有獨有的方式來
//計算hashCode三個對象的hashCode值不一樣,所以不是重複
//綜上所述:如果想要使三個對象重複,可以通過覆寫equals與hashCode方法
TreeSet:無重複的原則只有一個方法起作用:compareTo,上述的方法不是每個對象都有的,若想將某一個對象存入TreeSet集合中,需要讓對象所屬的類實現接口Comparable,實現接口後將ComparatorTo方法重寫,返回int,負數靠前排布,正數排列靠後。(有序)
TreeSet<Person> set = new TreeSet<>();
set.add(new Person("張三"));
System.out.println(set);
//會產生異常,執行結果如下:
Exception in thread "main" java.lang.ClassCastException: bittech.Person cannot be cast to java.lang.Comparable
at java.util.TreeMap.compare(TreeMap.java:1294)
at java.util.TreeMap.put(TreeMap.java:538)
at java.util.TreeSet.add(TreeSet.java:255)
//TreeSet源碼
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
//TreeMap源碼
public V put(K key, V value) {
Entry<K,V> t = root;
if (t == null) {
compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
綜上所知:將某一個對象存入TreeSet集合中,需要讓對象所屬的類實現接口Comparable,實現接口後將ComparatorTo方法重寫
正解:
class Person implements Comparable<Person>{
private String name;
public Person(String name){
this.name = name;
}
@Override
public int compareTo(Person o) {
return this.name.compareTo(o.name);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
public class Test2 {
public static void main(String[] args) {
TreeSet<Person> set = new TreeSet<>();
set.add(new Person("張三"));
System.out.println(set);
}
}
//執行結果如下:
[Person{name='張三'}]