Java基础-day09-set和hashmap

Set接口

Set接口:也称Set集合,但凡是实现了Set接口的类都叫做Set集合
特点: 元素无索引,元素不可重复(唯一)
HashSet集合: 实现类–元素存取无序
LinkedHashSet集合:实现类–元素存取有序
TreeSet集合:实现类–> 对元素进行排序
注意:
1.Set集合没有特殊的方法,都是使用Collection接口的方法
2.Set集合没有索引,所以遍历元素的方式就只有: 增强for循环,或者迭代器

HashSet集合存储数据的结构(哈希表)

在JDK1.8之前,哈希表底层采用数组+链表实现,即使用数组处理冲突,同一hash值的链表都存储在一个数组里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间.

简单的来说,哈希表是由数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的
Java基础-day09-set和hashmap_第1张图片

Java基础-day09-set和hashmap_第2张图片

HashSet存储自定义类型元素

给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一.


package com.claire.day13;

import java.util.Objects;

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, 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 String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Test2 {
    public static void main(String[] args) {
        Person p1 = new Person("张三", 19);
        Person p2 = new Person("张三", 20);
        Person p3 = new Person("张三", 19);
        Person p4 = new Person("张三", 19);

//        System.out.println(p1.equals(p2));
        HashSet<Person> set = new HashSet<>();
        set.add(p1);
        set.add(p2);
        set.add(p3);
        set.add(p4);
        System.out.println(set);
    }
}

由于重写了equals和hashCode方法, 所以存储的元素就唯一了
在这里插入图片描述

Map集合

//内部一个HashMap——HashSet内部实际上是用HashMap实现的
 private transient HashMap<E,Object> map;
 // transient 不会被序列化
/**
     * 构造一个新的HashSet,
     * 内部实际上是构造了一个HashMap
 public HashSet() {
        map = new HashMap<>();
    }

HashSet的add方法源码解析

  public boolean add(E e) {
  //内部实际上添加到map中,键:要添加的对象,值:Object对象
        return map.put(e, PRESENT)==null;
    }
public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>{}
public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

}

Java基础-day09-set和hashmap_第3张图片

Map集合的特点: K用来限制键的类型,V用来限制值的类型
         1.Map集合存储元素是以键值对的形式存储,每一个键值对都有键和值
         2.Map集合的键是唯一,值可以重复,如果键重复了,那么值就会被覆盖
         3.根据键取值

Map集合子类:
    - HashMap:存储数据采用的哈希表结构,元素的存取顺序不能保证一致。
                    由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。

    - LinkedHashMap:HashMap下有个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构。
               通过链表结构可以保证键值对的存取顺序一致;
               通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。

    - TreeMap:TreeMap集合和Map相比没有特有的功能,底层的数据结构是红黑树;
                可以对元素的键进行排序,排序方式有两种:自然排序和比较器排序

Map的常用方法

Map接口中定义了很多方法,常用的如下:

  • public V put(K key, V value): 把指定的键与指定的值添加到Map集合中。
  • public V remove(Object key): 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
  • public V get(Object key) 根据指定的键,在Map集合中获取对应的值。
  • public boolean containsKey(Object key):判断该集合中是否有此键
  • public Set keySet(): 获取Map集合中所有的键,存储到Set集合中。
  • public Set> entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)。
package com.claire.day13;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Test3 {
    public static void main(String[] args) {
        // 可以自定义索引的数组
       Map<String, String> map = new HashMap<>();
       map.put("name", "张三");
       map.put("addr", "沈阳市");
       map.put("age", "22");
       map.put("age", "30");
       System.out.println(map); //{name=张三, addr=沈阳市, age=22}
        // 获取
        String name = map.get("name");
        System.out.println(name);
       String v = map.remove("addr");
        System.out.println(v);

        System.out.println(map);
        // 判断是否包含指定的键
        System.out.println(map.containsKey("name"));
        System.out.println(map.containsKey("addr"));
        // 判断是否包含指定的键
        Set<String> keys = map.keySet();
        System.out.println(keys);

        Set<Map.Entry<String, String>> entries = map.entrySet();
        System.out.println(entries);
        // 遍历
        System.out.println("-------遍历1--------");
        for (String key: keys){
            String val = map.get(key);
            System.out.println("k = " + key+ " value + " + val);
        }
        System.out.println("-------遍历2--------");
        Set<Map.Entry<String, String>> entrySet = map.entrySet();
        for(Map.Entry<String, String> entry: entrySet){
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println("k = " + key+ " value + " + value);

        }

    }
}

map自定义类型存储


package com.claire.day13;

import java.util.Objects;

public class Student {
    private String name;
    private int age;
    private String id;

    public Student() {
    }



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

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    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 boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(id, student.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", id='" + id + '\'' +
                '}';
    }
}
package com.claire.day13;

import java.util.HashMap;

public class Test4 {
    public static void main(String[] args) {
        HashMap<Student, String> map = new HashMap<>();
        Student s1 = new Student("张三", 12, "22321312312");
        Student s2 = new Student("李四", 12, "12312312");
        Student s3 = new Student("王五", 12, "3213213213");
        Student s4 = new Student("赵六", 12, "312321321321");

        map.put(s1, "北京");
        map.put(s2, "上海");
        map.put(s3, "广州");
        map.put(s4, "深圳");
        System.out.println(map);
        System.out.println(map.size());

    }
}


Map集合练习

需求

  • 输入一个字符串统计该字符串中每个字符出现次数。

分析

  • 获取一个字符串对象
  • 创建一个Map集合,键代表字符,值代表次数。
  • 遍历字符串得到每个字符。
  • 判断Map中是否有该键。
  • 如果没有,第一次出现,存储次数为1;如果有,则说明已经出现过,获取到对应的值进行++,再次存储。
  • 打印最终结果

实现

package com.claire.day13;

import java.util.HashMap;

public class Test5 {
    public static void main(String[] args) {
        //        - 获取一个字符串对象
            String s = "dasdsadsadsadasa";

//         - 创建一个Map集合,键代表字符,值代表次数。
        HashMap<Character, Integer> map = new HashMap<>();
//        - 遍历字符串得到每个字符。
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            //     - 判断Map中是否有该键。
            //    - 如果没有,第一次出现,存储次数为1;如果有,则说明已经出现过,获取到对应的值进行++,再次存储。
            if (map.containsKey(c)){
                Integer val = map.get(c);
                val++;
                map.put(c, val);
            }else {
                map.put(c, 1);
            }

        }
        System.out.println(map);

//        - 打印最终结果
    }
}

你可能感兴趣的:(Java基础精讲,java,哈希算法,散列表)