Java教程

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

本文主要是介绍java-集合 - Set接口->HashSet , Map接口->HashMap ,集合类的嵌套组合,Collections工具类的基本应用。,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

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

这篇关于java-集合 - Set接口->HashSet , Map接口->HashMap ,集合类的嵌套组合,Collections工具类的基本应用。的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!