黑马程序员--集合框架(二)Set

时间:2023-02-18 17:41:07

----------------- android培训java培训、期待与您交流!-----------------


Set<>接口--
无序的集合,不允许重复元素,最多允许一个null元素。Set实现的基础是hashMap结构
集合之所以能保证元素唯一性是:
      1   当集合添加存储元素时,首先调用hashCode()方法判断哈希值是否相同,不相同则保存数据。
      2   当哈希值相同时,调用equals()方法判断是否相同


一  
HashSet   

上述set集合特点适用于HashSet。HashSet 的实现其实非常简单,它只是封装了一个 HashMap 对象来存储所有的集合元素,
所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。  HashSet 的绝大部分方法都是通过调用 HashMap 的方法来实现的,因此 HashSet 和 HashMap 两个集合在实现本质上是相同的。 

下面来看看具体代码实现hashset集合

class persion {

private String name;
private int age;
persion(String name,int age){
this.name = name;
this.age = age;
}

@Override
public int hashCode() {
//重写hashCode(),根据对象获取它的哈希值
System.out.println("----hashcode------");
return name.hashCode() + age*5;
}
@Override
public boolean equals(Object obj) {
// 重写equals()方法,当上述hashCode返回值相同时,就调用此方法判断是否相同
//自定义判断的方法--
//如:在此我们假设如果这人的姓名与年龄都相同,我们就认为他们是同一个人(简单的判断下,能说明问题就行)
System.out.println("--equals-----");
if (obj instanceof persion) {
persion p = (persion)obj;
return this.name.equals(p.name) && this.age == p.age ;
}else return false;
}
@Override
public String toString() {
// 重写toString方法
return "name="+this.name+" age="+this.age;
}
}


public class SetDemo {

public static void main(String[] args) {
hashsetD();
}

public static void hashsetD(){
Set<persion> st =new HashSet<persion>(); //创建set集合
st.add(new persion("zhanghui", 20)); //添加persion对象
st.add(new persion("lisi", 31));
st.add(new persion("wangwu", 18));
st.add(new persion("afei", 57));
st.add(new persion("lisi", 31));
st.remove(new persion("lisi", 31)); //删除persion对象
st.contains(new persion("afei", 57)); //判断是否包含该persion对象
for (Iterator<persion> it = st.iterator(); it.hasNext();) { //便利集合对象
System.out.println(it.next());
}
}

}
上述代码的执行效果是

----hashcode------
----hashcode------
----hashcode------
----hashcode------
----hashcode------
--equals-----
----hashcode------
--equals-----
----hashcode------
--equals-----
name=zhanghui  age=20
name=afei  age=57
name=wangwu  age=18

上述代码中创建了persion类,复写了hashcode,equals,toString方法用以对hashSet集合进行操作。
从结果中我们可以知道,当对集合添加数据时,首先调用的是hashCode()方法,判断哈希值是否相同。因为前4个对象不同所以就只调用hashcode方法。而当我们添加的第五个对象new  persion(“lisi”,31)时,因为和前面的相同,所以调用了hashcode方法后,又调用了equals()方法来判断。判断完毕后,发现对象相同,所以没有添加进去。同样的对于集合的remove()-删除元素,以及contains()-是否包含元素的方法,都是根据hashcode(),equals()方法来判断的。



二   TreeSet   基于二叉树的结构实现

    拥有默认的自然排序(前提是该对象具有比较性),也可以自定义比较器排序。

下面来看看具体代码

class persion implements Comparable<persion>{  //Comparable<>接口强制让对象具备比较性
private String name;
private int age;
persion(String name,int age){
this.name = name;
this.age = age;

@Override
public int compareTo(persion p) {
//实现Comparable接口,复写compareTo方法--是对象具有比较性
//根据方法返回的值---负整数、零或正整数,判断对象是小于、等于还是大于指定对象。
System.out.println("this:"+this.name+"---compareTo---"+"p:"+p.name);
if (this.age > p.age) {
//在此我们以年龄去比较对象
return 1;
}
if(this.age == p.age){
//在年龄相等时比较姓名---这调用的字符串的compareTo方法--
return this.name.compareTo(p.name);
}
//都不符合就是小于的情况,所以返回-1;
return -1;
}
@Override
public String toString() {
//重写toString方法
return this.name+"-----"+this.age;
}
}


public class SetDemo {

public static void main(String[] args) {
treeSetD();
}

public static void treeSetD(){
TreeSet<persion > ts =new TreeSet<persion>();
ts.add(new persion("zhanghui", 20)); //当第一次对集合添加元素时,直接添加
//System.out.println("1");
ts.add(new persion("lisi", 31));//集合中已有元素时,需要调用compareTo--来判断
ts.add(new persion("wangwu", 18));
ts.add(new persion("afei", 57));
ts.add(new persion("lisi1", 31));
boolean a =ts.remove(new persion("afei", 57)); //删除对象,返回boolean
System.out.println(a);
ts.contains(new persion("lisi", 31));//是否包含对象
for (Iterator<persion> it = ts.iterator(); it.hasNext();) {
System.out.println(it.next());
}
}
}
上述代码的执行效果是

this:lisi---compareTo---p:zhanghui
this:wangwu---compareTo---p:zhanghui
this:afei---compareTo---p:zhanghui
this:afei---compareTo---p:lisi
this:lisi1---compareTo---p:zhanghui
this:lisi1---compareTo---p:lisi
this:lisi1---compareTo---p:afei
this:afei---compareTo---p:zhanghui
this:afei---compareTo---p:lisi1
this:afei---compareTo---p:afei
true
this:lisi---compareTo---p:zhanghui
this:lisi---compareTo---p:lisi1
this:lisi---compareTo---p:lisi
wangwu-----18
zhanghui-----20
lisi-----31
lisi1-----31
从上面的执行效果我们可以知道,treeset集合第一次添加元素时,直接添加。集合中有元素时,就会调用compareTo方法比较排序。我们来通过一张图来看它的存储方式

黑马程序员--集合框架(二)Set

它的存储是以第一个元素为根节点,后面锁添加的元素都是首先对根节点去比较,大的放左边小的放右边。这样依次比较下去。就如当我们添加(“lisi1”31)时,先去比较(zhanghui,20)发现比它大就去与(lisi,31)比较,还是比它大就再去与(afei,57)比较,比它小所以就放在(afei,57)的右边。对于treeset集合的remove,和contains也都调用compareTo方法。这是让treeset集合具有排序功能的一种方法。

下面来看看第二种方法实现Comparator接口,重写compare方法就自定义比较器。

class persionComp implements Comparator<persion>{
//实现Comparator接口,复写compare方法
//当元素自身不具备比较性时,或者具备的比较性不是所需要的。
//这时就需要让集合自身具备比较性。
//在集合初始化时,就有了比较方式。
@Override
public int compare(persion p1, persion p2) {
int num;
if (p1.getAge()>p2.getAge()) {
return -1;
}
if (p1.getAge() ==p2.getAge()) {
return p1.getName().compareTo(p2.getName());
}
return 1;
}
}
创建完比较器后我们只要在创建treeset集合是传参进去就可以了。如:

 TreeSet<persion> ts =new TreeSet<persion>(new persionComp());这就是一个带比较器的set集合。

Set总结  

 无序集合,不允许重复元素,最多一null集合。加入集合的自定义对象必须重写equals方法用来确保对象唯一。具体功能有子类实现

1  HashSet --  基于hashMap结构。线程不同步,存取速度快。自定义的类必须重写equals,hashCode方法。

2  TreeSet --   基于二叉树结构,线程不同步,通过compareTo,compare方法实现对象唯一,排序。