Set及其子类

来源:互联网 发布:2017科普知识网络大赛 编辑:程序博客网 时间:2024/06/18 00:30

概述

  Collection        |--List            有序(存储顺序和取出顺序一致),可重复        |--Set            无序(存储顺序和取出顺序不一致),唯一  HashSet:它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。      注意:虽然Set集合的元素无序,但是,作为集合来说,它肯定有它自己的存储顺序,           而你的顺序恰好和它的存储顺序一致,这代表不了有序,你可以多存储一些数据,就能看到效果。
package cn.itcast_01;import java.util.HashSet;import java.util.Set;public class SetDemo {    public static void main(String[] args) {        // 创建集合对象        Set<String> set = new HashSet<String>();        // 创建并添加元素        set.add("hello");        set.add("java");        set.add("world");        set.add("java");        set.add("world");        // 增强for        for (String s : set) {            System.out.println(s);        }    }}

HashSet的唯一性

问题:为什么存储字符串的时候,字符串内容相同的只存储了一个呢?  通过查看add方法的源码,我们知道这个方法底层依赖 两个方法:hashCode()和equals()。  步骤:        首先比较哈希值        如果相同,继续走,比较地址值或者走equals()        如果不同,就直接添加到集合中    按照方法的步骤来说:            先看hashCode()值是否相同            相同:继续走equals()方法                返回true: 说明元素重复,就不添加                返回false:说明元素不重复,就添加到集合            不同:就直接把元素添加到集合  如果类没有重写这两个方法,默认使用的Object()。一般来说不同相同。  而String类重写了hashCode()和equals()方法,所以,它就可以把内容相同的字符串去掉。只留下一个。
package cn.itcast_02;import java.util.HashSet;/* * HashSet:存储字符串并遍历 */public class HashSetDemo {    public static void main(String[] args) {        // 创建集合对象        HashSet<String> hs = new HashSet<String>();        // 创建并添加元素        hs.add("hello");        hs.add("world");        hs.add("java");        hs.add("world");        // 遍历集合        for (String s : hs) {            System.out.println(s);        }    }}
  需求:存储自定义对象,并保证元素的唯一性  要求:如果两个对象的成员变量值都相同,则为同一个元素。  目前是不符合我的要求的:因为我们知道HashSet底层依赖的是hashCode()和equals()方法。  而这两个方法我们在学生类中没有重写,所以,默认使用的是Object类。  这个时候,他们的哈希值是不会一样的,根本就不会继续判断,执行了添加操作。
package cn.itcast_02;import java.util.HashSet;public class HashSetDemo2 {    public static void main(String[] args) {        // 创建集合对象        HashSet<Student> hs = new HashSet<Student>();        // 创建学生对象        Student s1 = new Student("林青霞", 27);        Student s2 = new Student("柳岩", 22);        Student s3 = new Student("王祖贤", 30);        Student s4 = new Student("林青霞", 27);        Student s5 = new Student("林青霞", 20);        Student s6 = new Student("范冰冰", 22);        // 添加元素        hs.add(s1);        hs.add(s2);        hs.add(s3);        hs.add(s4);        hs.add(s5);        hs.add(s6);        // 遍历集合        for (Student s : hs) {            System.out.println(s.getName() + "---" + s.getAge());        }    }}/*学生类*/package cn.itcast_02;/** * @author Administrator *  */public class Student {    private String name;    private int age;    public Student() {        super();    }    public Student(String name, int age) {        super();        this.name = name;        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    @Override    public int hashCode() {        final int prime = 31;        int result = 1;        result = prime * result + age;        result = prime * result + ((name == null) ? 0 : name.hashCode());        return result;    }    @Override    public boolean equals(Object obj) {        if (this == obj)            return true;        if (obj == null)            return false;        if (getClass() != obj.getClass())            return false;        Student other = (Student) obj;        if (age != other.age)            return false;        if (name == null) {            if (other.name != null)                return false;        } else if (!name.equals(other.name))            return false;        return true;    }    // @Override    // public int hashCode() {    // // return 0;    // // 因为成员变量值影响了哈希值,所以我们把成员变量值相加即可    // // return this.name.hashCode() + this.age;    // // 看下面    // // s1:name.hashCode()=40,age=30    // // s2:name.hashCode()=20,age=50    // // 尽可能的区分,我们可以把它们乘以一些整数    // return this.name.hashCode() + this.age * 15;    // }    //    // @Override    // public boolean equals(Object obj) {    // // System.out.println(this + "---" + obj);    // if (this == obj) {    // return true;    // }    //    // if (!(obj instanceof Student)) {    // return false;    // }    //    // Student s = (Student) obj;    // return this.name.equals(s.name) && this.age == s.age;    // }    //    // @Override    // public String toString() {    // return "Student [name=" + name + ", age=" + age + "]";    // }}

HashSet存储元素保证唯一性的代码及图解

HashSet的子类LinkedHashSet

  LinkedHashSet:底层数据结构由哈希表和链表组成。  哈希表保证元素的唯一性。  链表保证元素有素。(存储和取出是一致)
package cn.itcast_04;import java.util.LinkedHashSet;public class LinkedHashSetDemo {    public static void main(String[] args) {        // 创建集合对象        LinkedHashSet<String> hs = new LinkedHashSet<String>();        // 创建并添加元素        hs.add("hello");        hs.add("world");        hs.add("java");        hs.add("world");        hs.add("java");        // 遍历        for (String s : hs) {            System.out.println(s);        }    }}

TreeSet

  TreeSet:能够对元素按照某种规则进行排序。  排序有两种方式      A:自然排序      B:比较器排序  TreeSet集合的特点:排序和唯一 通过观察TreeSet的add()方法,我们知道最终要看TreeMap的put()方法。

自然排序

package cn.itcast_05;import java.util.TreeSet;public class TreeSetDemo {    public static void main(String[] args) {        // 创建集合对象        // 自然顺序进行排序        TreeSet<Integer> ts = new TreeSet<Integer>();        // 创建元素并添加        // 20,18,23,22,17,24,19,18,24        ts.add(20);        ts.add(18);        ts.add(23);        ts.add(22);        ts.add(17);        ts.add(24);        ts.add(19);        ts.add(18);        ts.add(24);        // 遍历        for (Integer i : ts) {            System.out.println(i);        }    }}

TreeSet存储元素自然排序和唯一的图解

  TreeSet存储自定义对象并保证排序和唯一。  A:你没有告诉我们怎么排序        自然排序,按照年龄从小到大排序  B:元素什么情况算唯一你也没告诉我        成员变量值都相同即为同一个元素
package cn.itcast_05;import java.util.TreeSet;public class TreeSetDemo2 {    public static void main(String[] args) {        // 创建集合对象        TreeSet<Student> ts = new TreeSet<Student>();        // 创建元素        Student s1 = new Student("linqingxia", 27);        Student s2 = new Student("zhangguorong", 29);        Student s3 = new Student("wanglihong", 23);        Student s4 = new Student("linqingxia", 27);        Student s5 = new Student("liushishi", 22);        Student s6 = new Student("wuqilong", 40);        Student s7 = new Student("fengqingy", 22);        // 添加元素        ts.add(s1);        ts.add(s2);        ts.add(s3);        ts.add(s4);        ts.add(s5);        ts.add(s6);        ts.add(s7);        // 遍历        for (Student s : ts) {            System.out.println(s.getName() + "---" + s.getAge());        }    }}/*学生类*/package cn.itcast_05;/* * 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口 */public class Student implements Comparable<Student> {    private String name;    private int age;    public Student() {        super();    }    public Student(String name, int age) {        super();        this.name = name;        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    @Override    public int compareTo(Student s) {        // return 0;        // return 1;        // return -1;        // 这里返回什么,其实应该根据我的排序规则来做        // 按照年龄排序,主要条件        int num = this.age - s.age;        // 次要条件        // 年龄相同的时候,还得去看姓名是否也相同        // 如果年龄和姓名都相同,才是同一个元素        int num2 = num == 0 ? this.name.compareTo(s.name) : num;        return num2;    }}

比较器排序

  需求:请按照姓名的长度排序  TreeSet集合保证元素排序和唯一性的原理  唯一性:是根据比较的返回是否是0来决定。  排序:        A:自然排序(元素具备比较性)            让元素所属的类实现自然排序接口 Comparable        B:比较器排序(集合具备比较性)            让集合的构造方法接收一个比较器接口的子类对象 Comparator
package cn.itcast_07;import java.util.Comparator;import java.util.TreeSet;public class TreeSetDemo {    public static void main(String[] args) {        // 创建集合对象        // TreeSet<Student> ts = new TreeSet<Student>(); //自然排序        // public TreeSet(Comparator comparator) //比较器排序        // TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());        // 如果一个方法的参数是接口,那么真正要的是接口的实现类的对象        // 而匿名内部类就可以实现这个东西        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {            @Override            public int compare(Student s1, Student s2) {                // 姓名长度                int num = s1.getName().length() - s2.getName().length();                // 姓名内容                int num2 = num == 0 ? s1.getName().compareTo(s2.getName())                        : num;                // 年龄                int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;                return num3;            }        });        // 创建元素        Student s1 = new Student("linqingxia", 27);        Student s2 = new Student("zhangguorong", 29);        Student s3 = new Student("wanglihong", 23);        Student s4 = new Student("linqingxia", 27);        Student s5 = new Student("liushishi", 22);        Student s6 = new Student("wuqilong", 40);        Student s7 = new Student("fengqingy", 22);        Student s8 = new Student("linqingxia", 29);        // 添加元素        ts.add(s1);        ts.add(s2);        ts.add(s3);        ts.add(s4);        ts.add(s5);        ts.add(s6);        ts.add(s7);        ts.add(s8);        // 遍历        for (Student s : ts) {            System.out.println(s.getName() + "---" + s.getAge());        }    }}

练习题

  键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台  分析:        A:定义学生类        B:创建一个TreeSet集合        C:总分从高到底如何实现呢?              D:键盘录入5个学生信息        E:遍历TreeSet集合
package cn.itcast_08;import java.util.Comparator;import java.util.Scanner;import java.util.TreeSet;public class TreeSetDemo {    public static void main(String[] args) {        // 创建一个TreeSet集合        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {            @Override            public int compare(Student s1, Student s2) {                // 总分从高到低                int num = s2.getSum() - s1.getSum();                // 总分相同的不一定语文相同                int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;                // 总分相同的不一定数序相同                int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2;                // 总分相同的不一定英语相同                int num4 = num3 == 0 ? s1.getEnglish() - s2.getEnglish() : num3;                // 姓名还不一定相同呢                int num5 = num4 == 0 ? s1.getName().compareTo(s2.getName())                        : num4;                return num5;            }        });        System.out.println("学生信息录入开始");        // 键盘录入5个学生信息        for (int x = 1; x <= 5; x++) {            Scanner sc = new Scanner(System.in);            System.out.println("请输入第" + x + "个学生的姓名:");            String name = sc.nextLine();            System.out.println("请输入第" + x + "个学生的语文成绩:");            String chineseString = sc.nextLine();            System.out.println("请输入第" + x + "个学生的数学成绩:");            String mathString = sc.nextLine();            System.out.println("请输入第" + x + "个学生的英语成绩:");            String englishString = sc.nextLine();            // 把数据封装到学生对象中            Student s = new Student();            s.setName(name);            s.setChinese(Integer.parseInt(chineseString));            s.setMath(Integer.parseInt(mathString));            s.setEnglish(Integer.parseInt(englishString));            // 把学生对象添加到集合            ts.add(s);        }        System.out.println("学生信息录入完毕");        System.out.println("学习信息从高到低排序如下:");        System.out.println("姓名\t语文成绩\t数学成绩\t英语成绩");        // 遍历集合        for (Student s : ts) {            System.out.println(s.getName() + "\t" + s.getChinese() + "\t"                    + s.getMath() + "\t" + s.getEnglish());        }    }}
  编写一个程序,获取10个1至20的随机数,要求随机数不能重复。  分析:        A:创建随机数对象        B:创建一个HashSet集合        C:判断集合的长度是不是小于10            是:就创建一个随机数添加            否:不搭理它        D:遍历HashSet集合
package cn.itcast_08;import java.util.HashSet;import java.util.Random;public class HashSetDemo {    public static void main(String[] args) {        // 创建随机数对象        Random r = new Random();        // 创建一个Set集合        HashSet<Integer> ts = new HashSet<Integer>();        // 判断集合的长度是不是小于10        while (ts.size() < 10) {            int num = r.nextInt(20) + 1;            ts.add(num);        }        // 遍历Set集合        for (Integer i : ts) {            System.out.println(i);        }    }}

终极练习题

  模拟斗地主洗牌和发牌  分析:        A:创建一个牌盒        B:装牌        C:洗牌        D:发牌        E:看牌  思路:        A:创建一个HashMap集合        B:创建一个ArrayList集合        C:创建花色数组和点数数组        D:从0开始往HashMap里面存储编号,并存储对应的牌。同时往ArrayList里面存储编号即可。        E:洗牌(洗的是编号)        F:发牌(发的也是编号,为了保证编号是排序的,就创建TreeSet集合接收)        G:看牌(遍历TreeSet集合,获取编号,到HashMap集合找对应的牌)
package cn.itcast_04;import java.util.ArrayList;import java.util.Collections;import java.util.HashMap;import java.util.TreeSet;public class PokerDemo {    public static void main(String[] args) {        // 创建一个HashMap集合        HashMap<Integer, String> hm = new HashMap<Integer, String>();        // 创建一个ArrayList集合        ArrayList<Integer> array = new ArrayList<Integer>();        // 创建花色数组和点数数组        // 定义一个花色数组        String[] colors = { "♠", "♥", "♣", "♦" };        // 定义一个点数数组        String[] numbers = { "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q",                "K", "A", "2", };        // 从0开始往HashMap里面存储编号,并存储对应的牌,同时往ArrayList里面存储编号即可。        int index = 0;        for (String number : numbers) {            for (String color : colors) {                String poker = color.concat(number);                hm.put(index, poker);                array.add(index);                index++;            }        }        hm.put(index, "小王");        array.add(index);        index++;        hm.put(index, "大王");        array.add(index);        // 洗牌(洗的是编号)        Collections.shuffle(array);        // 发牌(发的也是编号,为了保证编号是排序的,就创建TreeSet集合接收)        TreeSet<Integer> fengQingYang = new TreeSet<Integer>();        TreeSet<Integer> linQingXia = new TreeSet<Integer>();        TreeSet<Integer> liuYi = new TreeSet<Integer>();        TreeSet<Integer> diPai = new TreeSet<Integer>();        for (int x = 0; x < array.size(); x++) {            if (x >= array.size() - 3) {                diPai.add(array.get(x));            } else if (x % 3 == 0) {                fengQingYang.add(array.get(x));            } else if (x % 3 == 1) {                linQingXia.add(array.get(x));            } else if (x % 3 == 2) {                liuYi.add(array.get(x));            }        }        // 看牌(遍历TreeSet集合,获取编号,到HashMap集合找对应的牌)        lookPoker("风清扬", fengQingYang, hm);        lookPoker("林青霞", linQingXia, hm);        lookPoker("刘意", liuYi, hm);        lookPoker("底牌", diPai, hm);    }    // 写看牌的功能    public static void lookPoker(String name, TreeSet<Integer> ts,            HashMap<Integer, String> hm) {        System.out.print(name + "的牌是:");        for (Integer key : ts) {            String value = hm.get(key);            System.out.print(value + " ");        }        System.out.println();    }}

模拟斗地主洗牌和发牌并对牌进行排序的原理图解

0 0
原创粉丝点击