Java集合类总结2——Set

一、Set接口

Set是一种不包含重复的元素的CollectionSet最多有一个null元素。很明显,Set的构造函数有一个约束条件,传入的Collection参数不能包含重复的元素。
继承结构:

 publicinterface Set<E> extends Collection<E>{}
 publicabstract class AbstractSet<E> extends AbstractCollection<E>implements Set<E>{}
 public classCopyOnWriteArraySet<E>extends AbstractSet<E>implementsSerializable{}
 public abstract class EnumSet<E extendsEnum<E>>extends AbstractSet<E>implements Cloneable,Serializable{}
 public class HashSet<E>extendsAbstractSet<E>implements Set<E>, Cloneable,Serializable{}
 public final class JobStateReasonsextendsHashSet<JobStateReason>implements PrintJobAttribute{}
 publicclass LinkedHashSet<E>extends HashSet<E>implementsSet<E>, Cloneable, Serializable{}
 public classTreeSet<E>extends AbstractSet<E>implements SortedSet<E>,Cloneable,Serializable{}

可以看出,可以实例化的类为: HashSet LinkedHashSet TreeSet CopyOnWriteArraySet

java中向set中添加对象,如何确保不相同,需要看hashcode()equals()compareTo()方法的作用。


二:HashSet

1)Hashset数据结构:

publicclass HashSet<E> extends AbstractSet<E> implementsSet<E>, Cloneable, java.io.Serializable{
static finallong serialVersionUID = -5024744406713321676L;
privatetransient HashMap<E,Object> map;

//这是每个键所指的对像
privatestatic final Object PRESENT = new Object();

publicHashSet() {
map = new HashMap<E,Object>();
}
publicboolean add(E o) {
return map.put(o,PRESENT)==null;
}
//以下省略..........
}

可以看到 HashSet 使用了 HashMap 作为其 Map 保存“键-值”对。 Map 中的元素是键-值对,其中必须是唯一的 ,HashSet 就是利用这个特性实现没有重复元素的。它把 set 中的元素作为 Map 中的,从而保持元素的唯一性。


2) HashSet 应用实践——重写hashCodeequeals

publicclasstest{

publicstaticvoidmain(String[] args) {

Setset = newHashSet();

set.add(newSetElement5("aa"));

set.add(newSetElement5("aa"));

set.add(newSetElement5("bb"));

System.out.println(set);

}


staticclassSetElement5 {

Strings;


publicSetElement5(String s) {

this.s= s;

}


publicString toString() {

returns;

}


publicbooleanequals(Object obj) {

returns.equals(((SetElement5)obj).s);

}


publicinthashCode() {

//return super.hashCode();

returns.hashCode();

}

}


运行结果:[aa,bb]
SetElement5
重写了hashCode方法和euqals方法。HashSet中是采用了先比较元素hashCode如果相同则比较equals的方法来判断元素是否相同(duplicate),如果不重写,则不同的对象(前两个对象)即可视为不同


3
具体应用:

我们可以重写hashCode,equals方法,如联系人类Contact.java 每个联系人都有一个唯一ID,相同ID的不同contact对象我们视为相同,不能添加到set中,

这样new2contact,如果id相同,则视为相同对象

publicinthashCode()

{

returngetId().hashCode();

}


publicbooleanequals(Object c)

{

if(c == this)

{

returntrue;

}


if(c instanceofContact)

{

if(getId() != null&& getId().equals(((Contact) c).getId()))

{

returntrue;

}

}

returnfalse;

}

  请注意:必须小心操作可变对象。如果一个Set中的可变元素改变了自身状态导致Object.equals(Object)=true将导致一些问题。

4HashSet相关算法:从数组a中剔除数组a和数组b中含有的共同元素

publicclass Test1 {

public static void main(String[] args){

String a[] = {"a","a","b","c","d","d"};

String b[] = {"a","c","d","d","e","e"};

HashSet mHashSet = new HashSet();

for(int i = 0; i < b.length; i++){

if(!mHashSet.contains(b[i]));

mHashSet.add(b[i]);

}

for(int j = 0; j < a.length; j++){

if(!mHashSet.contains(a[j]))

System.out.println(a[j]);
}
}
}


二、 TreeSet
1)TreeSet
数据结构

TreeSet的部分实体:

publicclass TreeSet<E> extends AbstractSet<E> implementsSortedSet<E>, Cloneable, java.io.Serializable
{
privatetransient SortedMap<E,Object> m;
private transientSet<E> keySet;
//这是每个键所指的对像
privatestatic final Object PRESENT = new Object();

privateTreeSet(SortedMap<E,Object> m) {
this.m = m;
keySet= m.keySet();
}
public TreeSet() {
this(newTreeMap<E,Object>());
}
//以下省略..........
}

可以看到 TreeSet 使用了 SortedMap 作为其 Map 保存键-值对。 TreeSet 采用红黑二叉树的数据结构,添加到 TreeSet 中的数据会自动按升序排列。

2TreeSet应用实践——实Comparable接口

要用TreeSet来做为你的Set,那么Set中所装的元素都必须实现了Comparable接口。

publicclasstest7 {

publicstaticvoidmain(String[] args) {

Setset = newTreeSet();

set.add(newSetElement2("aa"));

set.add(newSetElement2("aa"));

set.add(newSetElement2("bb"));

System.out.println(set);

}


staticclassSetElement2 implementsComparable{

Strings;


publicSetElement2(String s) {

this.s= s;

}


publicString toString() {

returns;

}


publicintcompareTo(Objecto) {

returns.compareTo(((SetElement2)o).s);

}


publicbooleanequals(Object obj) {

returns.equals(((SetElement2)obj).s);

}

}

}


运行结果:[aa,bb]
要用TreeSet来做为你的Set,那么Set中所装的元素都必须实现了Comparable接口。TreeSet中是采用Comparable接口中的compareTo方法来判断元素是否相同(duplicate),而不是采用其他类似equals之类的东东来判断。

如果不实现该接口,程序能够正常编译,但是运行时会抛出异常java.lang.ClassCastException
因为在TreeSetadd方法中需要比较两个元素的。请看TreeMap中的compare方法:
privateint compare(K k1, K k2) {
return (comparator==null ?((Comparable</*-*/K>)k1).compareTo(k2):comparator.compare((K)k1, (K)k2));
}
可见这个方法先把要比较的元素downcastComparable类型。这里就可以解释示例程序1”中为什么会抛出异常java.lang.ClassCastExceptionSetElement1没有实现Comparable接口,当然就不能downcastComparable


3)如果重写compareTo,返回-1,如下:

public int compareTo(Object o){
//returns.compareTo(((SetElement3)o).s);
return -1;
}

运行结果:
[bb,aa, aa]
这是因为compareTo返回值始终是"-1",也就是说把任何元素都看成不同

4)排序,TreeSet中的数据会自动按升序排列,重写sort后,如下,按降序排列

public class test6 {

publicstaticvoidmain(String[] args) {

//Create a tree set

TreeSet<String>ts = newTreeSet<String>(newsort());

//Add elements to the tree set

ts.add("C");

ts.add("A");

ts.add("B");

ts.add("E");

ts.add("F");

ts.add("D");

//Get an iterator

Iterator<String>i = ts.iterator();

//Display elements

while(i.hasNext()) {

Objectelement = i.next();

System.out.print(element+ ",");

}

System.out.println();

}

}

classsort implementsComparator{

publicintcompare(Object a, Object b) {

StringaStr, bStr;

aStr= (String) a;

bStr= (String) b;

//重写compare方法

returnbStr.compareTo(aStr);

}

}

输出结果:F,E,D,C,B,A,

2.3 CopyOnWriteArraySet 部分:

CopyOnWriteArraySetjava.util.concurrent包中的一个类,它是线程安全的。
CopyOnWriteArraySet是使用CopyOnWriteArrayList作为其盛放元素的容器。当往CopyOnWriteArrayList添加新元素,它都要遍历整个List,并且用equals来比较两个元素是否相同。

public class test7 {

publicstaticvoidmain(String[] args) {

Setset = newCopyOnWriteArraySet();

set.add(newSetElement6("aa"));

set.add(newSetElement6("aa"));

set.add(newSetElement6("bb"));

System.out.println(set);

}


staticclassSetElement6 {

Strings;


publicSetElement6(String s) {

this.s= s;

}


publicString toString() {

returns;

}


publicbooleanequals(Object obj) {

returns.equals(((SetElement6)obj).s);

}

}

}
运行结果:[aa,bb]






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值