JANA-11.1-Set、HashSet与TreeSet;Map、HashMap与TreeMap讲解

集合Set
1.Set
  常用方法:直接查看api,里面的方法我们基本都是学过的
  Set的遍历 1:Iterator,2:foreach
2.HashSet(查询api看说明进行讲解)
  2.1 元素顺序:元素唯一,但是无序(它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变)
  2.2如何保证元素的唯一性的呢(分析源码)?
    通过简单的分析,我们知道HashSet集合保证元素的唯一性和add()方法相关。
    如何我们想深入的了解,就必须看add()方法的源码,看它的底层依赖什么内容?

//  if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {...}
//        
//      左边:e.hash == hash
//          比较对象的哈希值。
//        
//      右边:((k = e.key) == key || key.equals(k))
//          左边:(k = e.key) == key
//              比较对象的地址值。
//        
//          右边:key.equals(k)
//              比较的是对象的内容是否相同。默认情况下比较的是地址值

结论:
  底层数据结构是哈希表。
  哈希表依赖两个方法:hashCode()和equals()
执行流程:
  首先判断哈希值是否相同,如果不同,就直接添加到集合。
    如果相同,继续执行equals(),看其返回值,
    如果是false,就直接添加到集合。
     如果是true,说明元素重复不添加。
使用注意事项:如果你看到哈希结构的集合,就要考虑可能需要重写这两个方法。add()方法,保证唯一性的原理(底层依赖于hashCode()和equals()方法,保证了元素的唯一性)。

package com.edu.study7;
//需求:举例说明元素唯一性
import java.util.HashSet;
public class HashSetDemo {
    public static void main(String[] args) {
        /**HashSet集合
         * 元素唯一,但是无序
         * 
         * 基本数据类型包装类以及String类中已经重写过hashCode()和equals()方法
         * 所以自动保证了元素唯一性
         */
        //创建HashSet集合
        HashSet<String> hashSet = new HashSet<String>();

        //给集合添加元素
        hashSet.add("hello");
        hashSet.add("world");
        hashSet.add("java");
        hashSet.add("hello");
        hashSet.add("php");
        hashSet.add("c");
        hashSet.add("你好哦");
        hashSet.add("heihei");

        //遍历
        for (String s : hashSet) {
            System.out.println(s);
        }
    }
}
//第一次运行结果:              第八次运行结果:
//      hello                       hello       
//      heihei                      c
//      c                           heihei
//      php                         php
//      你好哦                     你好哦
//      java                        java
//      world                       world

需求:自定义学生对象,保证 集合元素唯一性

package com.edu.study7;

public class Student {
    private String name;
    private int age;
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    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;
    }

}
package com.edu.study7;
//HashSet集合,自定义类中必须重写hashCode()和equals()方法,才可以保证元素唯一性
import java.util.HashSet;
import java.util.Iterator;
public class HashSetTest {
    public static void main(String[] args) {
        //创建HashSet集合
        HashSet<Student> hashSet = new HashSet<Student>();
        //创建学生对象
        Student s1 = new Student("张三",13);
        Student s2 = new Student("李四",13);
        Student s3 = new Student("王五",13);
        Student s4 = new Student("张三",13);
        //给集合添加元素
        hashSet.add(s1);
        hashSet.add(s2);
        hashSet.add(s3);
        hashSet.add(s4);

        //遍历
        Iterator<Student> it = hashSet.iterator();
        while (it.hasNext()) {
            Student s = it.next();
            System.out.println(s.getName()+" "+s.getAge());
        }
    }
}
//不重写输出结果:      重写:
//  李四 13               李四 13
//  张三 13               张三 13
//  王五 13               王五 13
//  张三 13

3.TreeSet(查看api,得出结论)
3.1 元素顺序:使用元素的自然顺序对元素进行排序,或者根据创建 set时提供的 Comparator进行排序(比较器排序),具体取决于使用的构造方法。
3.2 TreeSet集合的底层算法:二叉树

package com.edu.study8;
/**
 * 基本数据类包装类以及String类都实现Comparable接口
 * 且都重写了compareTo()方法
 */
import java.util.TreeSet;
public class TreeSetDemo {
    public static void main(String[] args) {
        //创建TreeSet集合
/**     TreeSet<String> treeSet = new TreeSet<String>();
        treeSet.add("hello");
        treeSet.add("world");
        treeSet.add("c");
        treeSet.add("java");

        //遍历
        for (String string : treeSet) {
            System.out.println(string);
        }
    //输出:
    //  c
    //  hello
    //  java
    //  world
*/

        TreeSet<Integer> ts = new TreeSet<Integer>();
        ts.add(12);
        ts.add(25);
        ts.add(89);
        ts.add(3);
        //遍历
        for (Integer i : ts) {
            System.out.println(i);
        }
    //输出结果: 
    //  3
    //  12
    //  25
    //  89
    }
}

3.3 元素要求, 加入自定义JavaBean
需求:存入学生对象(姓名,年龄),1.按年龄排序,2.姓名排序(自然排序实现Comparable接口,并重写comparaTo()方法)

package com.edu_04;
//新建Student类
public class Student implements Comparable<Student>{
    private String name;
    private int age;
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    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 String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }

    //实现Comparable接口的同时必须实现这个比较法
    @Override
    public int compareTo(Student s) {
        //就是写的是元素的比较规则,由你自己去动手写出
        //按照学生的年龄进行排序
        /**
         * 两个对象进行比较:
         * s
         * this
         */
        int num = this.age - s.age;
        //判断年龄是否相同,如果相同比较姓名
        /**
         * 写这个比较规则的时候注意两点:
         * 1.他有主要条件,先按照主要条件进行排序
         * 2.如果主要条件相同,就需要你自己分析出来他的次要条件,再去按照次要条件进行比较
         */
        int num2 = num==0?this.name.compareTo(s.name):num;
        return num2;
    }
}
package com.edu_04;
import java.util.TreeSet;
/**
 * java.lang.ClassCastException:类型转换异常
 * TreeSet集合有两种排序方式:至于哪两种排序方式,取决于他的构造器
 * 自然排序:无参构造public TreeSet()
 */
public class TreeSetDemo {
    public static void main(String[] args) {
        //创建TreeSet集合,存储自定义对象
        TreeSet<Student> ts = new TreeSet<Student>();

        //给集合中添加Student对象
        Student s = new Student("guodegang", 50);
        Student s6 = new Student("liuyifei", 50);
        Student s2 = new Student("zhangxueyou", 55);
        Student s3 = new Student("amu", 45);
        Student s4 = new Student("tf-boys", 18);
        Student s5 = new Student("wangfeng", 49);

        ts.add(s);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);

        //遍历集合
        for (Student student : ts) {
            System.out.println(student);
        }
    }
}

需求:创建set集合的时候,传入Comparator(比较器排序)进行排序,进行排序(比较器排序)

package com.edu_05;
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSetDemo {
    public static void main(String[] args) {
        //使用匿名内部类
        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                int num = s1.getAge() - s2.getAge();
                int num2 = num==0?s1.getName().compareTo(s2.getName()):num;
                return num2;
            }
        });

        //创建对象存入集合
        Student s = new Student("guodegang", 50);
        Student s6 = new Student("liuyifei", 50);
        Student s2 = new Student("zhangxueyou", 55);
        Student s3 = new Student("amu", 45);
        Student s4 = new Student("tf-boys", 18);
        Student s5 = new Student("wangfeng", 49);

        ts.add(s);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);

        //遍历集合
        for (Student student : ts) {
            System.out.println(student);
        }   
    }
}

4. HashSet与TreeSet的相同点与不同点
  相同点:
    单列集合,元素不可重复
  不同点
    1. 底层存储的数据结构不同
    HashSet底层用的是HashMap哈希表结构存储,而TreeSet底层用的是TreeMap树结构存储
    2.存储时保证数据唯一性依据不同
    HashSet是通过复写hashCode()方法和equals()方法来保证的,而TreeSet通过Compareable接口的compareTo()方法来保证的
    3.有序性不一样
    HashSet无序,TreeSet有序

集合Map
一 一对应的映射关系。这种关系的集合在java叫Map。
Map:将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
1. Map接口中的方法:

   A:删除功能
    void clear():移除集合中的所有键值对元素
    V remove(Object key):根据键移除键值对元素,并返回值
  B:判断功能
    boolean containsKey(Object key):判断集合中是否包含指定的键
    boolean containsValue(Object value):判断集合中是否包含指定的值
    boolean isEmpty():判断集合是否为空
  C:获取功能
    Set<Map.Entry<K,V>> entrySet():获取键值对对象的集合,遍历键值对对象,利用getKey(),getValue()取出键和值        
    V get(Object key):根据键获取值
    Set<k> keySet():获取所有的键
    Collection<v> values():获取所有的值
  D:添加功能
    V put(K key,V value):集合添加键值对
  E:长度功能
    int size():键值对对数。

2. HashMap
  2.1元素顺序:元素顺序不可预测
  2.2底层算法:哈希算法
  2.3对键没有要求(仅仅相对于TreeMap来说)

package com.edu.study12;
//练习:存入(String,String)进行练习
import java.util.HashMap;
import java.util.Set;
public class HashMapDemo {
    public static void main(String[] args) {
        //创建HashMap集合
        HashMap<String, String> hashMap = new HashMap<String, String>();
        //给集合添加元素
        hashMap.put("A", "a");
        hashMap.put("B", "b");
        hashMap.put("C", "c");
        hashMap.put("D", "d");
        hashMap.put("A", "e");
        //当后面存入的元素和前面的键的值相同的时候,前面的元素的值会被后面的元素的值代替

        Set<String> keySet = hashMap.keySet();
        for (String key : keySet) {
            System.out.println(key+" "+hashMap.get(key));
        }
    }
}
//  D d
//  A e
//  B b
//  C c

练习 :

package com.edu.study13;
public class Student {
    private String name;
    private int age;
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    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 String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }
}
package com.edu.study13;
//练习:存入(String,Student)
import java.util.HashMap;
import java.util.Set;

public class HashMapDemo {
    public static void main(String[] args) {
        //创建HashMap集合
        HashMap<String, Student> hashMap = new HashMap<String, Student>();
        //创建Student对象
        Student s1 = new Student("zhang",6);
        Student s2 = new Student("li",25);
        Student s3 = new Student("sun",17);
        Student s4 = new Student("zhang",6);
        //给集合中添加元素
        hashMap.put("中国", s1);
        hashMap.put("韩国", s2);
        hashMap.put("美国", s3);
        hashMap.put("日本", s4);
        //当后面存入的元素和前面的键的值相同的时候,前面的元素的值会被后面的元素的值代替

        //通过键找值
        Set<String> keySet = hashMap.keySet();
            //得到的Set本质上是HashSet,元素唯一,无序
            //而键为String类型,已经重写了hashCode()和equals()方法,故保证了唯一性
        for (String key : keySet) {//因为在Student类中重写toString()方法
            System.out.println(key+" "+hashMap.get(key));
        }
    }
}
//日本 Student [name=zhang, age=6]
//韩国 Student [name=li, age=25]
//美国 Student [name=sun, age=17]
//中国 Student [name=zhang, age=6]

练习:

package com.edu.study14;
public class Student {
    private String name;
    private int age;
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    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 String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }   
}
package com.edu.study14;
//传入(Student, String),进行练习
import java.util.HashMap;
import java.util.Set;
public class HashMapDemo {
    public static void main(String[] args) {
        //创建HashMap集合
        HashMap<Student, String> hashMap = new HashMap<Student, String>();
        //创建Student对象
        Student s1 = new Student("zhang",6);
        Student s2 = new Student("liu",13);
        Student s3 = new Student("sun",20);
        Student s4 = new Student("zhang",6);
        //给集合添加元素
        hashMap.put(s1, "美国");
        hashMap.put(s2, "中国");
        hashMap.put(s3, "韩国");
        hashMap.put(s4, "中国");

        //遍历
        Set<Student> keySet = hashMap.keySet();
            //此时的Set实质上是HashSet,元素唯一,无序
            //而键是Student类对象,应重写hashCode()和equals()方法,方可保证唯一性
            //在Student类中重写hashCode()和equals()方法

        for (Student key : keySet) {
            //在Student类中重写toString()方法
            System.out.println(key+"  "+hashMap.get(key));
        }

    }
}
//  Student [name=liu, age=13]  中国
//  Student [name=sun, age=20]  韩国
//  Student [name=zhang, age=6]  中国

3. Treemap
3.1元素顺序:元素顺序与键的排序规则有关
3.2底层算法:Tree算法
4. 遍历
集合遍历:①获取建的集合 ②遍历键 ③根据键找值foreach()

1.foreach():根据丈夫找妻子(根据键找值)
2.entrySet():(Set<Map.Entry<K,V>> entrySet())先找到夫妻的结婚证,再从结婚证里面找到丈夫和妻子(先找到键值对对象,再从键值对对象里面找到键和值)

练习:存入(Integer,String)

package com.edu_11;
import java.util.Set;
import java.util.TreeMap;

public class TreeMapDemo {
    public static void main(String[] args) {
        //1.存入(Integer,String),主要验证排序方式
        //c创建TreeMap集合
        TreeMap<Integer, String> tm = new TreeMap<Integer, String>();
        //存入元素
        tm.put(1, "赵");
        tm.put(4, "刘");
        tm.put(2, "坤");
        tm.put(3, "李");

        //遍历集合
        Set<Integer> keys = tm.keySet();
        for (Integer key : keys) {
            System.out.println(key+"  "+tm.get(key));
        }
    }
}
/**     1  赵
        2  坤
        3  李
        4  刘
*/

练习:存入(Student,String)
新建学生类

package com.edu_12;
public class Student implements Comparable<Student>{
    private String name;
    private int age;
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    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 String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }
    @Override
    public int compareTo(Student s) {
        //先按年龄排序,年龄相同按照姓名排序
        //int num = this.age - s.age;
        int num =s.age - this.age; 
        int num2 = num==0?this.name.compareTo(s.name):num;
        return num2;
    }
}

测试

package com.edu_12;
import java.util.Set;
import java.util.TreeMap;

public class TreeMapDemo {
    public static void main(String[] args) {
        // 2.存入(Student,String),键:Student   值:地址
        //创建TreeMap集合
        TreeMap<Student, String> tm = new TreeMap<>();

        //创建学生对相同
        Student s1 = new Student("郭德纲", 50);
        Student s2 = new Student("刘德华", 55);
        Student s3 = new Student("张学友", 58);
        Student s4 = new Student("黎明", 40);
        Student s5 = new Student("郭德纲", 50);

        //将元素存入集合
        tm.put(s1, "中国");
        tm.put(s2, "中国");
        tm.put(s3, "中国");
        tm.put(s4, "中国");
        tm.put(s5, "中国");

        //遍历集合
        Set<Student> keys = tm.keySet();
        for (Student s : keys) {
            System.out.println(s+"  "+tm.get(s));
        }   
    }
}
/** Student [name=张学友, age=58]  中国
    Student [name=刘德华, age=55]  中国
    Student [name=郭德纲, age=50]  中国
    Student [name=黎明, age=40]  中国
*/  

5. HashMap与TreeMap的相同点与不同点
  相同点:
  主要用于存储键(key)值(value)对,根据键得到值,因此键不允许键重复,但允许值重复。
  不同点:
  1.HashMap里面存入的键值对在取出的时候是随机的,也是我们最常用的一个Map.根据键可以直接获取它的值,具有很快的访问速度。在Map 中插入、删除和定位元素,HashMap 是最好的选择。
  2.TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值