ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java-集合 - Set接口->HashSet , Map接口->HashMap ,集合类的嵌套组合,Collections工具类的基本应用。

2022-08-13 01:02:14  阅读:130  来源: 互联网

标签:Map String 映射 void 接口 key 集合 new public


9.9、Set集合

Set 一个不包含重复元素的 collection。

实现类:HashSet类、LinkedHashSet类

1)特点:

Set 集合中的元素是无序的(LinkedHashSet除外),Set集合中是不存在下标的概念,所以肯定没有get(下标)方法,里面所有的元素都是不重复的。如果有重复的元素,如果此 Set 已包含该元素,则该调用不更改 Set 并返回 false

2)常用方法

方法摘要 
 boolean add(E e) 
          如果 set 中尚未存在指定的元素,则添加此元素(可选操作)。 
 boolean addAll(Collection<? extends E> c) 
          如果 set 中没有指定 collection 中的所有元素,则将其添加到此 set 中(可选操作)。 
 void clear() 
          移除此 set 中的所有元素(可选操作)。 
 boolean contains(Object o) 
          如果 set 包含指定的元素,则返回 true。 
 boolean containsAll(Collection<?> c) 
          如果此 set 包含指定 collection 的所有元素,则返回 true。 
 boolean equals(Object o) 
          比较指定对象与此 set 的相等性。 
 int hashCode() 
          返回 set 的哈希码值。 
 boolean isEmpty() 
          如果 set 不包含元素,则返回 true。 
 Iterator<E> iterator() 
          返回在此 set 中的元素上进行迭代的迭代器。 
 boolean remove(Object o) 
          如果 set 中存在指定的元素,则将其移除(可选操作)。 
 boolean removeAll(Collection<?> c) 
          移除 set 中那些包含在指定 collection 中的元素(可选操作)。 
 boolean retainAll(Collection<?> c) 
          仅保留 set 中那些包含在指定 collection 中的元素(可选操作)。 
 int size() 
          返回 set 中的元素数(其容量)。 
 Object[] toArray() 
          返回一个包含 set 中所有元素的数组。 
<T> T[] 
 toArray(T[] a) 
          返回一个包含此 set 中所有元素的数组;返回数组的运行时类型是指定数组的类型。 

3)迭代方式

增强 for 循环

迭代器

案例:

在HashSet中存储3个员工,每个员工要保存的信息是员工编号,员工姓名,员工年龄。并演示3种方式进行迭代,输出员工的信息。

在上题中添加一个重复的元素,并进行迭代,输出元素。查看

元素个数。 4个,要重写 equals 方法,就不会加入重复的元素了。

尝试添加null对象,是否可以添加? 可以添加 null 对象

import java.util.Objects;

public class Emp {
    private String empId;
    private String empName;
    private int empAge;

    public String getEmpId() {
        return empId;
    }

    public void setEmpId(String empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public int getEmpAge() {
        return empAge;
    }

    @Override
    public String toString() {
        return empId +
                ", " + empName +
                ", " + empAge;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Emp emp = (Emp) o;
        return empAge == emp.empAge && Objects.equals(empId, emp.empId) && Objects.equals(empName, emp.empName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(empId, empName, empAge);
    }

    public void setEmpAge(int empAge) {
        this.empAge = empAge;
    }

    public Emp(String empId, String empName, int empAge) {
        this.empId = empId;
        this.empName = empName;
        this.empAge = empAge;
    }
}


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

public class HashSetTest02 {
    public static void main(String[] args) {
        HashSet<Emp> empHashSet = new HashSet<>();
        empHashSet.add(new Emp("e001","小黄",20));
        empHashSet.add(new Emp("e002","中黄",22));
        empHashSet.add(new Emp("e003","大黄",28));
        empHashSet.add(new Emp("e003","大黄",28));
        //两个emp 地址值不同,集合中会重复打印
        //需要重写 Emp 的 equals方法,避免重复打印
        //增强 for 循环
        for (Emp emp : empHashSet) {
            System.out.println(emp);
        }

        System.out.println("============================");
        //迭代器
        Iterator<Emp> iterator = empHashSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

需求:Scanner接收用户输入一个字符串。“aaabbbccdd",过滤

重复字符。

import java.util.HashSet;
import java.util.Scanner;

public class test01 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.print("输入字符串:");
        String str = input.next(); //“aaabbbccdd"
        char[] chars = str.toCharArray();
        HashSet<Character> hashSet = new HashSet<>();
        for (char ch : chars) {
            hashSet.add(ch);
        }
        for (Character chh : hashSet) {
            System.out.print(chh);
        } //abcd
    }
}

4)HashSet

关于 Set接口,建议观看韩顺平的B站视频学习

https://www.bilibili.com/video/BV1fh411y7R8?p=518&share_source=copy_web&vd_source=0e856227873a5eed50c1cf7df4a1b5a4

HahSet 原理

image

image

LinkedHashSet :

  1. LinkedHashSet 是 HashSet 的子类

  2. LinkedHashSet 底层是一个 LinkedHashMap ,底层维护了一个 数组+双向链表

  3. LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的

  4. LinkedHashSet 无重复元素

image

5)Set重复过滤的原理

1.如果是自定义对象类型:

对象默认的equals比较的是地址值

如果想不比较地址,比较属性,就重写equals方法

2.如果是String,Integer等(包装类的 equals 方法已经修改过)。

比较内容

9.10、Map 集合

将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。

1)Map 的特点?什么是双列集合?

1)Map 与 Collection 并列存在。用于保存具有映射关系的数据 :Key - Value

2)Map 中的 key 和 value 可以是任何引用类型的数据,会封装到HashMap$Node 对象中

3)Map 中的 key 不允许重复。keySet

4)Map 中的 value 可以重复

5)Map 的 key 可以为 null,value 也可以为null,注意 key 为 null,只能有一个,value 为 null,可以多个

6)key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到对应的 value

image

2)Map总结

1.HashMap的扩容机制和底层跟HashSet基本一致,数组+单向链

表,HashMap使用了key和value来保存数据,而HashSet只使用了

key来保存数据。

2.HashMap无序的,只能保存一个null的key,如果key一样,就是

覆盖操作。

3)常用API

void clear() 
          从此映射中移除所有映射关系(可选操作)。 
 boolean containsKey(Object key) 
          如果此映射包含指定键的映射关系,则返回 true。 
 boolean containsValue(Object value) 
          如果此映射将一个或多个键映射到指定值,则返回 true。 
 Set<Map.Entry<K,V>> entrySet() 
          返回此映射中包含的映射关系的 Set 视图。 
 boolean equals(Object o) 
          比较指定的对象与此映射是否相等。 
 V get(Object key) 
          返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。 
 int hashCode() 
          返回此映射的哈希码值。 
 boolean isEmpty() 
          如果此映射未包含键-值映射关系,则返回 true。 
 Set<K> keySet() 
          返回此映射中包含的键的 Set 视图。 
 V put(K key, V value) 
          将指定的值与此映射中的指定键关联(可选操作)。 
 void putAll(Map<? extends K,? extends V> m) 
          从指定映射中将所有映射关系复制到此映射中(可选操作)。 
 V remove(Object key) 
          如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。 
 int size() 
          返回此映射中的键-值映射关系数。 
 Collection<V> values() 
          返回此映射中包含的值的 Collection 视图。 

4)HashMap

建议观看韩顺平B站上的视频学习:

https://www.bilibili.com/video/BV1fh411y7R8?p=537&share_source=copy_web&vd_source=0e856227873a5eed50c1cf7df4a1b5a4

HashMap 小结

image

HashMap 底层机制及源码剖析:

image

image

5)HashTable

image

Hashtable 和 HashMap 对比:

image

6)循环遍历 Map 方式

遍历方式一:

  1. 获取 key 的集合 keySet() 方法
  2. 通过 key 获取 value get(key) 方法

遍历方式二:

  1. 通过 entrySet() 方法获取 entry 对象,里面就包含了所有的 key 和 value
Set<Map.Entry<k,v>> entrySet()
    返回此映射所包含的映射关系的 Set 视图
  1. 在通过 entry 对象的 getKey() 和 getValue() 来获取数据。
k getKey()
    返回与此项对应的键
v getValue()
    返回与此项对应的值
    
public interface Map<K,V> {
    //内部接口
    interface Entry<K,V> {
        K getKey();
        V getValue();
   }
}

7)练习

需求:Scanner接收用户输入一个字符串。“aaabbbccdd",

过滤重复字符并统计重复次数。

public static void main(String[] args) {
    Scanner input = new Scanner(System.in);
    System.out.print("请输入一个字符串:");
    //aaabbbccdd
    String str = input.next();
    //1.先把字符串转换为字符数组
    char[] chars = str.toCharArray();
    //2.创建HashMap集合
    HashMap<Character, Integer> map = new HashMap<>();
    //key - 字符   value - 次数
    for (char ch : chars) {
        //定义一个变量:保存次数
        int count = 1;
        //如果key存在
        if(map.containsKey(ch)){
            //2-1: 先从a中获取次数
            count = map.get(ch);
            //2-2:然后在基础上+1
            count++;
        }
        //2-3:把次数重新放入集合中
        map.put(ch,count);
    }
    //遍历
    Set<Character> keySet = map.keySet();
    for (Character key : keySet) {
        System.out.println(key + ":" + map.get(key));
    }
}

9.11、嵌套组合

集合中放入集合:

如:

List<Map<String,对象类型>> list = new ArrayList();

Map<Integer,Map<String,对象类型>> map2 = new HashMap<>();

案例:

public class Student {

    private String name;
    private int age;
    private double score;

    public Student(String name, int age, double score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    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;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }
}


public class TestStu {

    public static void main(String[] args) {
        Map<String, Student> map = new HashMap<>();
        map.put("A001",new Student("小强",21,39.5));
        map.put("A002",new Student("赵四",22,59.5));
        map.put("A003",new Student("张三",21,69.5));
        System.out.println("学号\t\t姓名\t\t年龄\t\t成绩");
        //遍历集合
        Set<String> keySet = map.keySet();
        Iterator<String> iterator = keySet.iterator();
        while (iterator.hasNext()){
            String stuId = iterator.next();
            Student student = map.get(stuId);
            System.out.println(stuId+"\t\t"+student.getName()+"\t\t"+student.getAge()+"\t\t"+student.getScore());
        }

        //嵌套集合
        List<Map<String,Student>> list = new ArrayList<>();
        Map<Integer,Map<String,Student>> map2 = new HashMap<>();
    }
}

9.12、Collections工具类的基本应用

作用:是集合的工具类,方便集合的操作。

常用的方法:

1)排序:根据元素的自然顺序 对指定列表按升序进行排序。

void sort(List<T> list)
          根据元素的自然顺序 对指定列表按升序进行排序。
@Test
    public void test01(){
        //根据元素的自然顺序 对指定列表按升序进行排序。
        List<Integer> list = Arrays.asList(34,56,14,68,45,89);
        Collections.sort(list);
        System.out.println("list = " + list);
    }

排序方式扩展:= 了解

需求:想对对象中的属性进行排序???

实现步骤:

1)实现 Comparable 接口

2)实现compareTo()方法

比较的规则:比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。

如果满足该规则,升序排序。

如果规则相反,降序 排序。

此对象:当前创建的对象 : this

指定对象:传入的对象Object o

int compareTo(T o)
          比较此对象与指定对象的顺序。

注意:因为String类默认重写了compareTo方法,所有可以直接比较。(比较的规律不确定)

案例:

需求:

在集合中存储学生对象,然后对学生的年龄进行升序排序。

如果年龄相同的情况下,想对分数进行升序排序。

如果年龄相同的情况下,想对姓名进行升序排序。

o: 传入的对象

this: 当前对象

规则:当前对象和传入的对象的age属性进行相减对比,

分别返回负数,零,正数。

升序排序

总结:

当前对象.属性 - 传入的对象.属性 - 升序

传入的对象.属性 - 当前对象.属性 - 降序

字符串的比较:直接调用compareTo方法

@Test
public void test02(){
    List<Student> list = Arrays.asList(
        new Student("柳岩",21,39.5),
        new Student("张三",22,59.5),
        new Student("李四",22,25.5),
        new Student("周富强",19,89.5),
        new Student("徐志胜",22,78.5)
    );
    /**
         * 需求:
         * 	在集合中存储学生对象,然后对学生的年龄进行升序排序。
         * 	如果年龄相同的情况下,想对分数进行升序排序。
         * 	如果年龄相同的情况下,想对姓名进行升序排序。
         */
    //排序
    Collections.sort(list);
    System.out.println(list);
}


public class Student implements Comparable<Student>{

    private String name;
    private int age;
    private double score;

    public Student(String name, int age, double score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    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;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                "}\n";
    }

    //如果要实现对象的比较,那么必须实现compareTo方法
    /*
        o: 传入的对象
        this: 当前对象
        规则:当前对象和传入的对象的age属性进行相减对比,分别返回负数,零,正数。
              升序排序
        总结:
            当前对象.属性 - 传入的对象.属性 -  升序
            传入的对象.属性 - 当前对象.属性 -  降序
     */
    @Override
    public int compareTo(Student o) {
       /* if(this.getAge() - o.getAge() < 0){
            return -1;
        }else if(this.getScore() - o.getScore() > 0){
            return 1;
        }
        return 0;*/
        //优化
       /* return (this.getAge() - o.getAge())==0?
                (int)(this.getScore()-o.getScore()):(this.getAge() - o.getAge());*/
        //满足年龄的情况下,对字符串排序
        return (o.getAge() - this.getAge())==0?
                (this.getName().compareTo(o.getName())):(o.getAge() - this.getAge());
        
        //如果一定要按中文比较
        //Comparator<Object> comparator = Collator.getInstance(Locale.CHINA);
        //return (o.getAge() - this.getAge()) == 0 ? 
            //(comparator.compare(o.getName(),this.getName())) : (o.getAge() - this.getAge())
    }
}

2)2分查找法

static <T> int 			binarySearch(List list, T key)          使用二分搜索法搜索指定列表,以获得指定对象。

3)反转集合元素

static void 			reverse(List<?> list)           反转指定列表中元素的顺序。

4)替换所有元素

static <T> void 		fill(List<? super T> list, T obj) 3          使用指定元素替换指定列表中的所有元素。

5)随机置换元素位置:洗牌

static void 			shuffle(List<?> list)           使用默认随机源对指定列表进行置换。

9.13、如何选择集合实现类:

image

标签:Map,String,映射,void,接口,key,集合,new,public
来源: https://www.cnblogs.com/hwphwc/p/16581816.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有