Set;HashSet;LinkedHashSet;Set如何保证元素唯一;Map集合 (Java Day15)

一,Set

  • 概述:他是单列集合的无序集合,他是所有无序集合的顶层接口。里面的所有功能就是无序集合的共性功能;但是他没有独有的功能,他的功能都是Collection里面的功能,使用的时候就是用Collection接口里面的功能
  • 特点:
  1. 存取数据的顺序不一致【无序】
  2. 没有索引【无索引】
  3. 存放的元素要唯一,不可重复。【元素唯一】
  4. 常见的使用场景:用来进行去重。
  • Set的子类

  • HashSet:

  1. ​ 概述:就是单纯体现无序集合的功能,没有自己特有的功能,体现无序集合的特点。

代码示例:


import java.util.HashSet;
import java.util.Iterator;
public class Demo_HashSet {
public static void main(String[] args) {
    //创建HashSet集合
    //构造方法
    HashSet<String> set=new HashSet<>();
    set.add("3");
    set.add("6");
    set.add("3");
    set.add("2");
    set.add("4");
    System.out.println(set); //输出的顺序无序,元素不重复唯一,无索引,如果是数字的话是从小到大排序的 [2, 3, 4, 6]
    set.remove("4");
    System.out.println(set); //[2, 3, 6]
    System.out.println(set.size()); //3

 

  • 遍历

 


import java.util.HashSet;
import java.util.Iterator;
public class Demo_HashSet {
public static void main(String[] args) {
    //创建HashSet集合
    //构造方法
    HashSet<String> set=new HashSet<>();
    set.add("3");
    set.add("6");
    set.add("3");
    set.add("2");
    set.add("4");
    System.out.println(set); //输出的顺序无序,元素不重复唯一,无索引,如果是数字的话是从小到大排序的 [2, 3, 4, 6]
    set.remove("4");
    System.out.println(set); //[2, 3, 6]
    System.out.println(set.size()); //3  //第一种:数组法遍历
    //集合转数组的时候不管集合是否给定具体的数据类型,都转变成Object类型的数组
    //弊端 遍历之后需要强制转换
    Object[] arr = set.toArray();
   for (int i = 0; i < arr.length; i++) {
        String s = (String) arr[i]; //集合已指定了泛型所以需要强转
        System.out.println(s);
    }
    System.out.println("========");
    
    //第二种:迭代器遍历
    //迭代器对象 [Iterator      ListIterator]
    Iterator<String> it = set.iterator(); //it 为获取的迭代器对象
    while (it.hasNext()) {
        String ss = (String)it .next();// ss 为得到的内容,承载 next()得到的东西
        System.out.println(ss);
    }
    System.out.println("========");

 

  • 第三种:增强for遍历
  • ​ 概述:理解为是对迭代器遍历的格式得封装改进
  • ​ 格式:for(数据类型 变量名 :容器对象名){拿到元素的处理逻辑}
  • ​ 解释:
  1. ​ for:关键字 代表了循环
  2. ​ 数据类型:容器中存放的数据的数据类型
  3. 变量名:变量 用来存储每次循环遍历得到的内容值
  4. 容器对象名:要遍历的容器
  5. ​ 好处:增强for单纯的进行遍历比较快捷简便
  6. ​ 弊端:遍历的过程中不能够进行相应的增删操作
  7. ​ 增强for的本质是什么?就是迭代器遍历

代码示例


import java.util.HashSet;
import java.util.Iterator;
public class Demo_HashSet {
public static void main(String[] args) {
    //创建HashSet集合
    //构造方法
    HashSet<String> set=new HashSet<>();
    set.add("3");
    set.add("6");
    set.add("3");
    set.add("2");
    set.add("4");
    System.out.println(set); //输出的顺序无序,元素不重复唯一,无索引,如果是数字的话是从小到大排序的 [2, 3, 4, 6]
    set.remove("4");
    System.out.println(set); //[2, 3, 6]
    System.out.println(set.size()); //3
    
 //增强for遍历
    for(String ss :set) {
        System.out.println(ss);
    }   
}
}
  • 总结:
  1. 数组法和迭代器以及增强for可以遍历所有的集合和数组。
  2. 普通for循环遍历能变遍历数组和有序集合【有索引的容器】

  • LinkedHashSet

  • ​ 概述:他是Set集合的一个实现类,同时也是HashSet的子类。他是无序集合中的有序集合,体现无序集合的另外两个特点【在存取顺序上LinkedHashSet是Set集合的叛徒】
  • ​ 特点:
  1. 存取有序【有序】
  2. 没有索引【无索引】
  3. 元素还是唯一不能重复【元素唯一不重复】
  4. ​ 没有自己特有的功能,他的功能和HashSet一样都是Collection的功能
  5. ​ 遍历也是和HashSet一样:数组法、迭代器、foreach

代码示例


import java.util.Iterator;
import java.util.LinkedHashSet;
public class Demo_LinkedHashSet {
public static void main(String[] args) {
    LinkedHashSet<String>set = new LinkedHashSet<>();
    set.add("春天");
    set.add("夏天");
    set.add("秋天");
    set.add("冬天");
    set.add("春天");
    set.add("夏至");
    set.add("冬至");
    System.out.println(set);//[春天, 夏天, 秋天, 冬天, 夏至, 冬至] 有序排列
    System.out.println("=======");
    
    //第一种:数组遍历
    Object[] arr = set.toArray();
  for (int i = 0; i < arr.length; i++) {
      String ss= (String)arr[i];
      System.out.println(ss);
}
  System.out.println("==========");
  
  //第二种:迭代器遍历
 Iterator<String>it = set.iterator();
 while (it.hasNext()) {
    String s = (String) it.next();
    System.out.println(s);
}
 System.out.println("==========");

 //第三种:增强for遍历,(foreach)
 for (String name : set) {  // 用name 去接收
    System.out.println(name);
}
}
}
  • 练习
  • 键盘录入一个字符串,输出其中的字符,相同字符只输出一次,要求保证原录入顺序
  • 分析:
  1. 键盘录入一个字符串
  2. 操作的是字符串的字符 【想办法得到字符串的字符】
  3. 挨个把字符存到LinkedHashSet中
  4. 遍历输出或直接输出集合的内容

代码示例


import java.util.LinkedHashSet;
import java.util.Scanner;
public class Test {
    public static void main(String[] args) {
        //1、键盘录入一个字符串
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串:");
        String line = sc.nextLine();
        //2、操作的是字符串的字符 【想办法得到字符串的字符】
        char[] cs = line.toCharArray();
        //创建一个LinkedHashSet的对象
        LinkedHashSet<Character> set = new LinkedHashSet<>();
        for (char c : cs) {
            //3、挨个把字符存到LinkedHashSet中
            set.add(c);
        }
        //4、遍历输出或直接输出集合的内容
        System.out.println(set);
    }
}

 

二,Set如何保证元素唯一

  • 重写hashCode
  • 重写equals方法
  • eclipse的操作:
  1. 使用快捷键,直接全部生成:alt + shift + s h
  2. hashCode:是一个native方法,返回的是对象的内存地址,重写这个方法可保证属性值相同的对象的哈希值是一样,不重写返回的哈希值不一样。
  3. hashSet集合 就是根据对象的哈希值来存放数据的
  • 原理:
  1. 调用被添加元素的hashCode(),和HashSet中已有元素的hashCode比较是否相同

​          1.1 、如果哈希值不相同,直接存储

​          1.2、 如果相同,需要调用equals方法比较是否相同

  • ​ 不相同,直接存储元素
  • ​ 相同,认为是同一元素.不存储

代码示例:

//定义一个Person类
public class Person { private String name; private int age; private String sex; //构造方法 public Person(String name, int age, String sex) { super(); this.name = name; this.age = age; this.sex = sex; } //重写 toString 方法 @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]"; } //重写 hashCode 方法 @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((sex == null) ? 0 : sex.hashCode()); return result; } //重写 equals 方法 @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (sex == null) { if (other.sex != null) return false; } else if (!sex.equals(other.sex)) return false; return true; } }

//定义一个测试类


import java.util.HashSet;
public class Demo01 {
public static void main(String[] args) {
    //创建HashSet
    HashSet<Person> set = new HashSet<>();
   //创建两个人物对象
    Person p = new Person("Jack", 22, "");
    Person p1= new Person("Jack", 22, "");
    System.out.println(" P的hashcode:"+p.hashCode());
    System.out.println(" P1的hashcode:"+p1.hashCode());
    System.out.println(p.equals(p1));//比较属性值
    System.out.println(p == p1); //比较地址值
    //因为没有重写方法所以比较的是地址值
    set.add(p1);
    set.add(p);
    System.out.println(set);
}
}

 

 

 

三,Map集合

  • 概述:他是集合体系中的双列集合。每个位置上存放的是一对 [两个] 数据。而且这对数据具有映射关系。
  • 映射关系:通过其一可以找到对应的另一个数据。比如:夫妻关系
  • 键值对数据:就是map集合位置上存放的那对数据。
  1. ​ 键:上面的数据有要求:唯一不可变 [在map集合的所有的键中]
  2. ​ 值:可以有重复的。
  3. 在map集合中的键值对中key [键] 比较重要 [只有通过key可以找对应的值,不能通过值来找到对应的键]
  • 比如:
  • ​ map特点:
  1. map集合是无序的
  2. 他的key值不能出现重复的值【key唯一】
  3. 他的值可以重复的
  4. 通过key可以精确的找到对应的值
  • Map集合的常用方法

  1. put(K k,V v):添加键值对数据到Map集合
  2. remove(K key):根据key删除该key的键值对数据
  3. ​ clear():清空map集合
  4. get(K key):根据Key获取对应的value值
  5. containsKey(K k):判断集合的所有key中是否包含参数k
  6. containsValue(V v):判断集合的所有value值中是否包含参数v

代码示例:


import java.util.HashMap;
import java.util.Map;
public class Demo_Map {
public static void main(String[] args) {
    //使用Map集合,map是一个接口 必须找他的实现类 使用hashMap
    Map<String, String> map = new HashMap<>();
    map.put("春天", "有花海");
    map.put("夏天", "有大海");
    map.put("秋天", "有果实");
    System.out.println(map);//{夏天=有大海, 秋天=有果实, 春天=有花海} 结果无序
    //为什么现实的不是地址值而是内容值,输出语句直接输出一个对象他是默认去调用toString方法,
    //首先执行自己类中的toString,自己没有执行父类中的toString方法
    map.put("春天", "春暖花开");
    System.out.println(map);//put方法除了添加的功能还有修改键的值的行为,两个功能,添加/修改
    map.remove("夏天");
    System.out.println(map); //key删除了,值也跟着被删除了
    String value=map.get("春天");
    System.out.println(value); //春暖花开,只找现任,不找前任,前任被替换掉了。
    System.out.println(map.containsKey("夏天"));//因为夏天已经被remove掉了 false
    System.out.println(map.containsValue("春暖花开"));//true
    System.out.println(map.keySet()); //[秋天, 春天]
    System.out.println(map.entrySet()); // [秋天=有果实, 春天=春暖花开]
    map.clear();
    System.out.println(map); //{}
    
}
}

 

练习

  • 键盘录入一个字符串,统计每个字符出现的次数 例如,录入aaaabbccddd!@#@#$@#$%cc66ff 
  • 打印出来:a有4个,b有2个,c有4个,d有3个,!有1个,@有3个,$有2个,%有1个,6有2个,f有2个

分析:

代码示例


import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class Map_Test {
public static void main(String[] args) {
    //1,键盘录入字符串
    Scanner sc= new Scanner(System.in);
    System.out.println("录入一个字符串:");
    String line = sc.nextLine();
    
    //2,获取所有字符串中有一个转换字符数组的方法
    char[] cs = line.toCharArray();

    //3,得到每一个字符和map集合的可以进行判断是否包含
    //创建map集合
    Map<Character, Integer> map= new HashMap<>();
    for (char c : cs) {
        //C就是每一个字符
        // 进行和map集合的可以进行判断是否包含
        if(map.containsKey(c)){
            //3.1,包含更新字符的个数到集合
            Integer value =map.get(c);
            value++;
            map.put(c, value);
    }else {
        //3.2,不包含添加字符到map集合
        map.put(c, 1);
    }
    }
    //4,输出map集合的内容
    System.out.println(map);
}
}

 

 

posted @ 2020-03-12 17:18  娜梓  阅读(540)  评论(0编辑  收藏  举报