【Java的集合框架之set 28】

一、Set集合

元素不可以重复,并且是无序的(也就是说不保证排序)

Set集合的方法和Collection方法一样,拿来直接用就行

二、常用的两个子类对象

|-- HashSet  内部数据结构是哈希表,是不同步的  -->实现排序是通过hashCode  和 equals进行比较

|-- TreeSet   按照元素字典顺序排序的,是不同步的 

  -->实现排序的方法一:让元素自身具备比较功能,也就是需要实现comparable接口,覆盖compareTo方法

     判断元素唯一性的方法:就是根据比较方法的返回结果是否是0 ,是0 就不存

     -->实现排序的方法二:如果对象中不具备自然排序或者是对象类不能进行修改,这时候就需要让集合本身具备排序功能(定义一个类实现comparator接口,覆盖compare方法,将该类对象作为  参数传递给TheeSet集合的构造函数)

三、详细介绍HashSet

--------举例演示HashSet----------

package com.JavaStudy01.Set;

import java.util.HashSet;
import java.util.Iterator;

/**
 * @Author wufq
 * @Date 2020/7/31 14:39
 */
public class HashSetDemo01 {
    public static void main(String[] args){
        HashSet  hs = new HashSet();

        hs.add("haha");
        hs.add("xixi");
        hs.add("hehe");
        hs.add("hehe");
        hs.add("hehe");
        hs.add("hehe");
        hs.add("heihei");

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

    }
}
=====执行结果====
haha
heihei
xixi
hehe

通过执行结果证明:Set集合确实是存放不重复的对象,并且还是无序的

1、Set集合的HashCode值

Set集合里面放的对象其实是通过hashCode算出来的值

哈希表:哈希是一种算法,算出来的值存储起来 就形成了哈希表

 

 2、HashSet存储自定义对象(要求:往HashSet集合里面存放person对象,如果姓名和年龄相同,视为同一个人。视为相同元素)

HashSet集合数据结构是哈希表,所以存储元素的时候使用元素的hashCode方法来确定位置,如果位置相同的话在用元素的equals方法来确定是否相同

举例说明:

package com.JavaStudy01.Set;

import com.JavaStudy01.Bean.Person;

import java.util.HashSet;
import java.util.Iterator;

/**
 * @Author wufq
 * @Date 2020/7/31 16:32
 * HashSet存储自定义对象
 */
public class HashSetDemo02 {
    public static void main(String[] args){
        HashSet hs = new HashSet();
        hs.add(new Person("lisi1",21));
        hs.add(new Person("lisi2",22));
        hs.add(new Person("lisi9",23));
        hs.add(new Person("lisi9",23));
        hs.add(new Person("lisi8",25));
        
        Iterator it=hs.iterator();
        while (it.hasNext()){
            Person p = (Person)it.next();
            System.out.println(p.getName()+"::"+p.getAge() );
        }
    }
}
=====执行结果=====
lisi1::21
lisi8::25
lisi9::23
lisi9::23
lisi2::22

通过执行结果发现,相同的姓名和年龄不是同一个元素,并且被打印出来了(不符合我们的要求)

分析原因:

因为person对象也是继承了Object对象,而Object类里面同样包含了hashcode方法,所以只要new了一个对象,就会有一个hashcode值,所以即使有两个hs.add(new Person("lisi9",23));
那么也会有两个不同的hashCode值,因此会打印出来

如何解决:

Person类重写hashCode()方法和equals()方法

package com.JavaStudy01.Bean;

/**
 * @Author wufq
 * @Date 2020/7/31 11:24
 */
public class Person extends Object{
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int hashCode() {
        System.out.println(this+"........hachCode");//验证是否真的在调用hashCode方法
        return name.hashCode()+age;
    }

    @Override
    public boolean equals(Object obj) {
        Person p= (Person)obj;

        System.out.println(this+"........equals"+obj);//验证是否真的在调用equals方法
        //this表示谁去调用就是谁
        return this.name.equals(p.name)&&this.age == p.age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String toString(){
        return name+"::"+age;
    }

}

这样在执行HashSetDemo02,结果就没有重复的内容了,并且可以看出hashSet确实是先计算hashcode的值,然后在计算equals

======重写equals,hashCode以后的执行结果=====

lisi1::21........hachCode
lisi2::22........hachCode
lisi9::23........hachCode
lisi9::23........hachCode
lisi9::23........equals lisi9::23
lisi8::25........hachCode
lisi1::21
lisi2::22
lisi8::25
lisi9::23

------>

可以看出lisi9::23  确实是先判断hashcode的值,然后在判断的是equals

-------->额外的知识点补充:<------------

 

 如果是存储对象,那么重写equals方法如下:

public boolean equals(Object obj) {
        Person p= (Person)obj;

        if(this == obj){
            return true;
        }
        if(!(obj instanceof Person)){
            throw new ClassCastException("类型不对!");
        }

    }

3、框架练习:

------->定义功能去除ArrayList中的重复元素

package com.JavaStudy01.Set;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * @Author wufq
 * @Date 2020/8/4 17:20
 * 定义功能去除ArrayList里面的重复元素--->去除重复的字符串
 */
public class ArrayListDemo03 {


    public static void main(String[] args){
        ArrayList al = new ArrayList();
        al.add("abc1");
        al.add("abc2");
        al.add("abc3");
        al.add("abc3");

        System.out.println("排重之前:"+al);
        al= getGetsingleElement(al);
        System.out.println("排重之后:"+al);
    }

    public static ArrayList getGetsingleElement(ArrayList al) {
        //1、定义一个临时容器
        ArrayList temp = new ArrayList();

        //2、迭代al集合
        Iterator it = al.iterator();
        while (it.hasNext()){
            Object obj=it.next();
            //3、判断比迭代到的元素是否在临时容器内
            if(!temp.contains(obj)){
                temp.add(obj);
            }
        }

        return temp;
    }

}
======执行结果======
排重之前:[abc1, abc2, abc3, abc3]
排重之后:[abc1, abc2, abc3]

-------->定义功能去除ArrayList中的重复自定义对象(这里只需要重写person类内的equals方法以及toString()方法)

package com.JavaStudy01.Set;

import com.JavaStudy01.Bean.Person;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * @Author wufq
 * @Date 2020/8/4 18:17
 * ArrayList去除重复的自定义对象
 */
public class ArrayListDemo02 {

    public static void main(String[] args){
        ArrayList ali = new ArrayList();
        ali.add(new Person("lisi1",23));
        ali.add(new Person("lisi2",22));
        ali.add(new Person("lisi3",21));
        ali.add(new Person("lisi4",20));
        ali.add(new Person("lisi1",23));

        System.out.println(ali);
        ali = StingElement(ali);
        System.out.println(ali);
    }

    private static ArrayList StingElement(ArrayList ali) {

        ArrayList temp = new ArrayList();

        Iterator it = ali.iterator();
        while (it.hasNext()){
            Object obj = it.next();
            if(!temp.contains(obj)){
                temp.add(obj);
            }

        }

        return temp;
    }

}
=======执行结果======
[lisi1::23, lisi2::22, lisi3::21, lisi4::20, lisi1::23]
[lisi1::23, lisi2::22, lisi3::21, lisi4::20]

注意:hashSet集合无论是包含或者删除一个元素,就需要判断该元素是否和容器内的元素是否相同,例如:对于ArrayList这样的集合,contains、remove需要重写hashCode和equals方法。hashSet集合只需要重写equals方法

 4、HashSet是无序并且不保证重复,为了改进引进了子类LinkedHashSet(---->有序并且是唯一的)

package com.JavaStudy01.Set;

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;


/**
 * @Author wufq
 * @Date 2020/8/6 09:28
 */
public class LinkedHashSet01 {
    public static void main(String[] args){
        HashSet hs = new LinkedHashSet();

        hs.add("haha");
        hs.add("xixi");
        hs.add("hehe");
        hs.add("hehe");
        hs.add("hehe");
        hs.add("hehe");
        hs.add("heihei");

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

    }
}
====执行结果====
haha
xixi
hehe
heihei

四、详细介绍TreeSet

1、比较基本数据类型

package com.JavaStudy01.Set;

import java.util.Iterator;
import java.util.TreeSet;

/**
 * @Author wufq
 * @Date 2020/8/6 09:53
 */
public class TreeSetDemo01 {
    public static void main(String[] args){
        TreeSet ts = new TreeSet();

        ts.add("aa");
        ts.add("abc");
        ts.add("zz");
        ts.add("hh");

        Iterator it = ts.iterator();

        while (it.hasNext()){
            System.out.println(it.next());
        }

    }

}
====执行结果====
aa
abc
hh
zz

通过执行结果发现:基本数据类型的元素按照元素字典进行排序

2、比较自定义类型(第一种比较方式:通过元素自身的比较方式)

------->TreeSetDemo02类:<---------

package com.JavaStudy01.Set;

import com.JavaStudy01.Bean.Person;

import java.util.Iterator;
import java.util.TreeSet;

/**
 * @Author wufq
 * @Date 2020/8/6 10:06
 */
public class TreeSetDemo02 {
    public static void main(String[] args){
        TreeSet ts = new TreeSet();
        ts.add(new Person("zhangsan",23));
        ts.add(new Person("lisi",24));
        ts.add(new Person("wangwu",25));
        ts.add(new Person("zhaoliu",26));

        Iterator it = ts.iterator();
        while (it.hasNext()){
            Person p = (Person)it.next();
            System.out.println(p.getName()+"::"+p.getAge());  //报com.JavaStudy01.Bean.Person cannot be cast to java.lang.Comparable异常
        }
    }

    /*
    Comparable:此接口强行对实现他的每一个类的对象进行整体排序,这种排序被称为类的自然排序,类的compareTo方法被称为自然比较方法
    如何才能解决可以比较的对象:

     */
}
=====执行结果=====
报com.JavaStudy01.Bean.Person cannot be cast to java.lang.Comparable异常
 

通过查Comparable异常发现:此接口强行对实现他的每一个类的对象进行整体排序,这种排序被称为类的自然排序,类的compareTo方法被称为自然比较方法

如何才能解决可以比较的对象:person类继承Comparable接口,并重写compareTo方法

int compareTo():比较此对象与指定对象的大小,如果该对象小于,大于,等于指定对象,则分别返回负整数,正整数,零

--------->Person类继承Comparable接口<---------

package com.JavaStudy01.Bean;

/**
 * @Author wufq
 * @Date 2020/7/31 11:24
 */
public class Person implements Comparable{
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int hashCode() {
//        System.out.println(this+"........hachCode");//验证是否真的在调用hashCode方法
        return name.hashCode()+age;
    }

    @Override
    public boolean equals(Object obj) {
        Person p= (Person)obj;

//        System.out.println(this+"........equals"+obj);//验证是否真的在调用equals方法
        //this表示谁去调用就是谁
        return this.name.equals(p.name)&&this.age == p.age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String toString(){
        return name+"::"+age;
    }

    @Override
    public int compareTo(Object o) {
        Person p = (Person)o;
        //通过年龄的大小进行判断,如果年龄相同在通过名字进行判断
        if(this.age < p.age){
            return -1;
        }else if(this.age > p.age){
            return 1;
        }else if(this.age == p.age){
            return this.name.compareTo(p.name);
        }

        //另外一种判断写法
        int temp = this.age - p.age;
        return temp==0?this.name.compareTo(p.name):temp;//temp=0吗,等于就对name进行比较,不等于就返回temp
    }
}

重新执行Person的结果:

zhangsan::23
lisi::24
wangwu::25
huqi::26
zhaoliu::26

------->通过结果可以看出已经完成了排序

 3、比较自定义类型(第二种比较方式:通过集合本身具备比较功能)

------->定义一个ComparatorByName类实现Comparator接口<---------

 

package com.JavaStudy01.Set;

import com.JavaStudy01.Bean.Person;

import java.util.Comparator;

/**
 * @Author wufq
 * @Date 2020/8/6 14:37
 */
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;
    }
}

 

------->TreeSetDemo02类<-------

 

package com.JavaStudy01.Set;

import com.JavaStudy01.Bean.Person;

import java.util.Iterator;
import java.util.TreeSet;

/**
 * @Author wufq
 * @Date 2020/8/6 10:06
 */
public class TreeSetDemo02 {
    public static void main(String[] args){
        TreeSet ts = new TreeSet(new ComparatorByName());
        ts.add(new Person("zhangsan",23));
        ts.add(new Person("lisi",24));
        ts.add(new Person("wangwu",25));
        ts.add(new Person("zhaoliu",26));
        ts.add(new Person("huqi",26));

        Iterator it = ts.iterator();
        while (it.hasNext()){
            Person p = (Person)it.next();
            System.out.println(p.getName()+"::"+p.getAge());  //报com.JavaStudy01.Bean.Person cannot be cast to java.lang.Comparable异常
        }
    }
}
======执行结果======
huqi::26
lisi::24
wangwu::25
zhangsan::23
zhaoliu::26

 

4、TreeSet底层结构,来判断如何确定元素的比较

 5、字符串长度排序

------->定义一个ComparatorByString类实现Comparator接口<---------

 

package com.JavaStudy01.Set;

import java.util.Comparator;

/**
 * @Author wufq
 * @Date 2020/8/6 15:27
 */
public class ComparatorByString 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; //这里的compareTo是String类自身的比较方法,而非集合内的比较方法
    }
}

 

------->TreeSetDemo03排序<---------

 

package com.JavaStudy01.Set;

import java.util.Iterator;
import java.util.TreeSet;

/**
 * @Author wufq
 * @Date 2020/8/6 15:27
 */
public class TreeSetDemo03 {
    public static void main(String[] args){
        TreeSet ts = new TreeSet(new ComparatorByString());

        ts.add("aa");
        ts.add("abcd");
        ts.add("zzzzzz");
        ts.add("hhl");
        ts.add("kkk");

        Iterator it = ts.iterator();

        while (it.hasNext()){
            System.out.println(it.next());
        }
    }

}
====执行结果=====
aa
hhl
kkk
abcd
zzzzzz

 

 

posted @ 2020-07-31 17:05  尘封~~  阅读(145)  评论(0编辑  收藏  举报