大数据------javase基础------day15

这篇具有很好参考价值的文章主要介绍了大数据------javase基础------day15。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Map

  • Map接口的特点

Map接口是键值对集合,每个元素均包含键和值两个对象

无序(存入顺序和遍历顺序不一致)

  • 键值对特点:

(1)键唯一,不可重复;但值可以重复

(2)键和值一一映射,一个键对应一个值(值可以是单个值也可以是个数组或集合)

  • 创建Map接口方式

(1)以多态的方式创建

(2)具体的实现类HashMap

Map接口常用方法

方法 解释
public V put(K key, V value) 将键值对存入集合
public V get(Object key) 返回指定键映射到的值,如果此映射不包含键的映射,则返回 null 。 (即用键取值)
pulblic int size() 返回此映射中键 - 值映射的数量。 (即返回该集合中键值对元素数量)
public V remove(Object key) 如果存在,则从该映射中移除键的映射(可选操作)。(即使用键作为检索条件来删除键值对)
default boolean remove(Object key, Object value) 仅当指定键当前映射到指定值时才删除该条目的条目。
public boolean isEmpty() 如果此映射不包含键 - 值映射,则返回 true 。(即判断该集合是否为空)
public boolean containsKey(Object key) 如果此映射包含指定键的映射,则返回 true 。 (即判断该集合中是否存在指定的键)
public boolean containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回 true 。(即判断该集合中是否有指定的值)
default V replace(K key, V value) 仅当指定键当前映射到某个值时,才替换该条目的条目。 (即用新值替换当前键所映射的值)
default boolean replace(K key, V oldValue, V newValue) 仅当前映射到指定值时,才替换指定键的条目。

注意:使用put方法时,若要存入的键是集合中已经存在的键的话,则此时会用新值替换掉原来该键所对应的值

public class TestOne {
    public static void main(String[] args) {
        Map map = new HashMap<>();
        map.put("班长", "美国");
        map.put("学委", "中国");//存入键值对
        map.put("体委", "俄罗斯");
        map.put("文委", "意大利");
        map.put("班委", "意大利");
        String s = (String) map.get("班长");//取出键所对应的值
        System.out.println(s);
        System.out.println(map);
        System.out.println("---------------------------");
        map.remove("学委");//使用键作为检索条件来删除键值对
        System.out.println(map);
        System.out.println("---------------------------");
        map.remove("班委", "意大利");
        System.out.println(map);
        System.out.println("---------------------------");
        System.out.println(map.isEmpty());
        System.out.println("---------------------------");
        System.out.println(map.containsKey("班委"));//判断集合中是否有指定的键
        System.out.println("---------------------------");
        System.out.println(map.containsValue("意大利"));//判断该集合中是否有指定的值
        System.out.println("---------------------------");
        map.replace("班长", "朝鲜");
        System.out.println(map);
        System.out.println("---------------------------");
        // 仅当前映射到指定值时,才替换指定键的条目
        System.out.println(map.replace("文委", "德国", "日本"));
        System.out.println("---------------------------");
        map.put("文委", "韩国");
        System.out.println(map);

    }
}

大数据------javase基础------day15,大数据全套体系知识点归纳--第一部分javase基础,java,开发语言

Map接口的遍历

  • 注意

(1)Map集合不能用iterator迭代器遍历,因为iterator()方法属于Collection集合中的方法

(2)Map集合也不能用增强for循环遍历,因为其底层用的是iterator迭代器遍历

(3)Map集合也不能用传统for循环遍历,因为其没有下标

(4)Map接口的遍历需要遍历键,因为每个键对应一个值

  • 用到的方法
方法 解释
public Set<K> keySet() 返回此映射中包含的键的Set视图。 (即返回键集,该键集会被存入不可重复的Set集合,从而可以使用iterator迭代器遍历)
public Collection<V> values() 返回此映射中包含的值的Collection视图。 (即返回值集,该值集会被存入可重复的Collection集合,从而可以使用iterator迭代器进行遍历)
public Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射的Set视图。 (即返回键值对集)
用到的静态嵌套类 解释
static interface Map.Entry<K,V> 映射条目(键值对)。 (即将获取到的键值转型为键值对)
静态嵌套类Entry中的方法 解释
public K getKey() 返回与此条目对应的键。
public V getValue() 返回与此条目对应的值。

问题

(1)为什么键集存入Collection集合中的Set集合?

因为键是无序且不可以重复的,而Set集合刚好是无序且不可重复的,所以若想要对Map集合进行遍历则需要先将其键集转换为Set集合,然后利用Collection集合中特有的方法iterator方法进行迭代器遍历

(2)为什么值集存入Collection集合?

因为值是跟着键走的,因为键是无序的,所以值是无序的,又因为虽然键是不能重复的,但是值是可以重复的,所以无法使用Collection集合中的两个子集合(List和Set),只能使用Collection集合

  • 遍历方式一------利用键集遍历
public class TestTwo {
    public static void main(String[] args) {
        Map map = new HashMap<>();
        map.put("班长", "美国");
        map.put("学委", "中国");//存入键值对
        map.put("体委", "俄罗斯");
        map.put("文委", "意大利");
        map.put("班委", "意大利");

        Set keys = map.keySet();//返回键集---该键集会被存入Set集合,从而可以使用iterator迭代器遍历
        Iterator iter = keys.iterator();//获取键集迭代器
        while(iter.hasNext()) {
            String key = (String) iter.next();
            String value = (String) map.get(key);
            System.out.println(key + "=" + value);
        }
    }
}

大数据------javase基础------day15,大数据全套体系知识点归纳--第一部分javase基础,java,开发语言

  • 遍历方式二------利用值集遍历
public class TestThree {
    public static void main(String[] args) {
        Map map = new HashMap<>();
        map.put("班长", "美国");
        map.put("学委", "中国");//存入键值对
        map.put("体委", "俄罗斯");
        map.put("文委", "意大利");
        map.put("班委", "意大利");

        Collection col = map.values();
        Iterator iter = col.iterator();
        while (iter.hasNext()) {
            String value = (String) iter.next();
            System.out.println(value);
        }
    }
}

大数据------javase基础------day15,大数据全套体系知识点归纳--第一部分javase基础,java,开发语言

  • 遍历方式三------利用键值集遍历
public class TestFour {
    public static void main(String[] args) {
        Map map = new HashMap<>();
        map.put("班长", "美国");
        map.put("学委", "中国");//存入键值对
        map.put("体委", "俄罗斯");
        map.put("文委", "意大利");
        map.put("班委", "意大利");

        Set set = map.entrySet();//返回键值对Set集合
        Iterator iter = set.iterator();//返回迭代器对象
        while (iter.hasNext()) {
            Map.Entry entry = (Map.Entry) iter.next();//将获取到的元素转换为键值对
            System.out.println(entry);//打印出键值对
            String key = (String) entry.getKey();//返回键
            String value = (String) entry.getValue();//返回值
            System.out.println("key = " + key + "\n" + "value = " + value);
            System.out.println("------------------------------");

        }
    }
}

大数据------javase基础------day15,大数据全套体系知识点归纳--第一部分javase基础,java,开发语言

  • Map接口的实现类

Map接口的常用实现类:HashMap、TreeMap、LinkedHashMap和Properties

HashMap和HashTable

  • 异同

(1)HashMap线程不安全,允许使用null键和null值,效率高,推荐使用

(2)HashTable线程安全,任何非null对象都可以用作键或值,效率低,不推荐使用

(3)底层用相同的方式(哈希表)存储元素

  • HashMap的实例有两个影响其性能的参数:初始容量和负载因子

(1)初始容量只是创建哈希表时的容量

(2)是在自动增加容量之前允许哈希表获取的完整程度的度量。 当哈希表中的条目数超过默认加载因子(0.75)和当前容量的乘积时,哈希表将被重新哈希(即,重建内部数据结构),以便哈希表具有大约两倍的桶数。

  • HashMap特点
    (1)创建HashMap对象时会为负载因子进行默认赋值为0.75
    (2)第一次调用put方法时初始化一个长度为16的数组
    (3)当集合中的元素数超过默认负载因子(0.75)和数组长度的乘积时按照原来数组长度的两倍扩容
    (4)在JDK1.8之前,HashMap底层使用链表+数组存储元素;在JDK1.8之后,HashMap底层使用链表+数组+红黑树存储
    (5)在JDK1.8之后,若一个链表元素超过8个此时数组长度达到64,则将链表结构变为红黑树

  • HashMap源码解析
    (1)负载因子
    大数据------javase基础------day15,大数据全套体系知识点归纳--第一部分javase基础,java,开发语言
    (2)调用put方法
    大数据------javase基础------day15,大数据全套体系知识点归纳--第一部分javase基础,java,开发语言
    因为创建Map集合时是利用HashMap多态的方式创建的,所以调用的put方法为HashMap类中的put方法,以上源码截图即为HashMap类中的put方法,其中HashMap源码中的putVal方法代码及解释如下:

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {
//tab为键值对数组,p为当前节点元素,n为当前数组长度,i为计算所得到的数组索引(即本次元素在数组中的下标)
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    //通过哈希码计算数组索引i并检查该位置的节点p是否为null,若为null则在该位置存入一个新节点
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
    //通过哈希码计算数组索引i并检查该位置的节点p不为null(代表该节点处有元素)
    else {
        Node<K,V> e; K k;
         //判断当前节点处的元素的哈希值与要存入的元素的哈希值是否相等且当前节点处的元素的键是否等于要存入的元素的键以及两键是否相等,若成立则说明要存入的元素与原元素相同则不执行新增操作
        //该if判断等同于hashcode和equals方法的结合体
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;//将新元素赋值给老元素
        //若不成立则说明要存入的元素与原元素不相同,此时需要判断要新增的元素节点是否是TreeNode的对象(即判断当前要存的节点是否是树节点(即红黑树)的对象),若是则存入树中
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        //若新增的元素节点不是树节点的对象则代表当前节点是链表中的节点,将该节点插入链表中
        else {
            //遍历循环链表,直至链表末尾
            for (int binCount = 0; ; ++binCount) {
                //将链表的下一个节点赋给e并判断该节点是否为空,若为空则将节点p作为一个新节点添加到链表中
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);
                    //判断链表增加节点后长度是否达到树化的阈值,若达到则调用方法将链表转化为树
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    break;//退出循环执行循环体后的代码
                }
                //若存在与要插入的节点相同的节点则直接跳出循环
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;将当前链表节点赋给p
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
    }

if ((tab = table) == null || (n = tab.length) == 0)该句代码中table的代码为transient Node<K, V>[] table

if ((tab = table) == null || (n = tab.length) == 0)
    n = (tab = resize()).length;

table 的初始化是在 putVal 方法中进行的,当第一次添加元素时,table 会被初始化为具有默认容量的数组。所以第一次使用put方法时集合中无元素,最开始table为空,此句代码含义为:将装数据的数组赋值给键值对数组tab,然后判断tab是否为null或者当前数组tab的长度是否为0,若是(就证明无法添加新元素)则需要利用HashMap源码中的resize方法来返回一个扩容后的新数组并将其赋给tab然后将该扩容后的新数组的长度赋值给n

if ((p = tab[i = (n - 1) & hash]) == null)
    tab[i] = newNode(hash, key, value, null);

通过哈希码计算数组索引i并检查该位置的节点p是否为null,若为null则在该位置创建一个新节点

注意:为什么用(n-1)&hash ?

保证计算出的索引值在数组长度范围内

用到的resize方法的代码如下:文章来源地址https://www.toymoban.com/news/detail-805842.html

final Node<K,V>[] resize() {
    //将当前元素数组赋给oldTab------旧节点数组
        Node<K,V>[] oldTab = table;
    //记录当前oldTab旧节点数组的长度;若为空则代表第一次存储元素,将长度记为0,否则记为当前数组长度
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
    //记录长度*负载因子之后得出的旧的扩容临界值(即旧的阈值),用于判断是否需要进行扩容。其中临界值threshold在HashMap类的构造器中利用其方法tableSizeFor计算
        int oldThr = threshold;
    //newCap为新的数组长度,newThr为新的扩容临界值---即定义新的容量和新的阈值
        int newCap, newThr = 0;
    //判断是否是第一次存储元素,若不是则执行if代码
        if (oldCap > 0) {
            //判断旧节点数组长度是否大于常量(static final int MAXIMUM_CAPACITY= 1 << 30),该常量为HashMap的最大容量
            if (oldCap >= MAXIMUM_CAPACITY) {
                //若旧节点数组长度大于HashMap的最大容量则将阈值设为最大值常数2^31 -1,表示不再进行扩容,直接返回旧节点数组
                threshold = Integer.MAX_VALUE;
                return oldTab;
            }
            //将旧节点数组长度扩大两倍赋给新节点newCap并判断若新容量小于MAXIMUM_CAPACITY(HashMap的最大容量)并且旧容量大于等于DEFAULT_INITIAL_CAPACITY(为HashMap的默认初始容量,为16),则将新阈值设为旧阈值的两倍。
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY)
                newThr = oldThr << 1; // double threshold
        }
    //若是第一次存储元素则判断旧阈值是否大于0
        else if (oldThr > 0) // initial capacity was placed in threshold
            newCap = oldThr;
    //若是第一次存储元素且旧阈值为0------即旧节点容量和旧阈值均为0  时,则将新容量设置为默认初始容量16,将新阈值设置为默认负载因子与默认初始容量的乘积12
        else {               // zero initial threshold signifies using defaults
            newCap = DEFAULT_INITIAL_CAPACITY;
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
    //若新阈值为0则判断新容量小于最大容量并且新容量乘以负载因子小于最大容量并为新阈值赋值
        if (newThr == 0) {
            float ft = (float)newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                      (int)ft : Integer.MAX_VALUE);
        }
        threshold = newThr;//更新阈值(扩容的临界值)
        @SuppressWarnings({"rawtypes","unchecked"})
        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
        table = newTab;
        if (oldTab != null) {
            for (int j = 0; j < oldCap; ++j) {
                Node<K,V> e;
                if ((e = oldTab[j]) != null) {
                    oldTab[j] = null;
                    if (e.next == null)
                        newTab[e.hash & (newCap - 1)] = e;
                    else if (e instanceof TreeNode)
                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                    else { // preserve order
                        Node<K,V> loHead = null, loTail = null;
                        Node<K,V> hiHead = null, hiTail = null;
                        Node<K,V> next;
                        do {
                            next = e.next;
                            if ((e.hash & oldCap) == 0) {
                                if (loTail == null)
                                    loHead = e;
                                else
                                    loTail.next = e;
                                loTail = e;
                            }
                            else {
                                if (hiTail == null)
                                    hiHead = e;
                                else
                                    hiTail.next = e;
                                hiTail = e;
                            }
                        } while ((e = next) != null);
                        if (loTail != null) {
                            loTail.next = null;
                            newTab[j] = loHead;
                        }
                        if (hiTail != null) {
                            hiTail.next = null;
                            newTab[j + oldCap] = hiHead;
                        }
                    }
                }
            }
        }
        return newTab;
    }

到了这里,关于大数据------javase基础------day15的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 【体系结构】山东大学计算机体系结构知识点清单

    【体系结构】山东大学计算机体系结构知识点清单

    涵盖所有考点,复习绝对高效,点赞+留邮箱获取pdf版本 1. 计算机系统的层次结构 语言实现的两种基本技术: 翻译:先把 N+1 级程序全部转换成 N 级程序后,再去执行新产生的 N 级程序,在执行过程中 N+1 级程序不再被访问。 解释:每当一条 N+1 级指令被译码后,就直接去执

    2024年02月11日
    浏览(70)
  • css知识学习系列(15)-每天10个知识点

    👍 点赞,你的认可是我创作的动力! ⭐️ 收藏,你的青睐是我努力的方向! ✏️ 评论,你的意见是我进步的财富! transition 属性用于创建元素状态变化的平滑过渡效果。您可以指定要过渡的属性、持续时间和过渡类型。 示例: transition: width 0.5s ease; 会使元素的宽度在0.

    2024年02月07日
    浏览(8)
  • 关于“Python”的核心知识点整理大全15

    关于“Python”的核心知识点整理大全15

    目录 ​编辑 7.3.2 删除包含特定值的所有列表元素 pets.py 7.3.3 使用用户输入来填充字典 mountain_poll.py 7.4 小结 第8章 函 数 8.1 定义函数 greeter.py 8.1.1 向函数传递信息 8.1.2 实参和形参 8.2.1 位置实参 2. 位置实参的顺序很重要 8.2.2 实参 往期快速传送门👆(在文章最后):

    2024年02月05日
    浏览(8)
  • Java体系性能测试进阶必须了解的知识点——死锁分析和锁竞争分析

    Java体系性能测试进阶必须了解的知识点——死锁分析和锁竞争分析

    所谓 死锁 ,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。对于锁更好的理解,先要理解monitor这个概念! monitor直译过来是监视器的意思,专业一点叫管程。monitor是属于编程语言级别的,它的出现

    2024年02月07日
    浏览(10)
  • 学习JavaSE基础-day1

    学习JavaSE基础-day1

    JRE 和 JDK JRE:Java运行环境,如果想要运行Java程序至少要安装JRE JDK:Java开发环境(开发工具包),如果要开发Java程序,必须安装JDK JRE = JVM + 核心类库 JDK = JRE + 开发工具包 JDK JRE JVM 关系如图所示:     JDK下载地址:www.oracle.com 配置Path环境变量:希望可以在命令窗口的任意的

    2024年02月07日
    浏览(11)
  • 数据结构—基础知识(15):哈夫曼树

    数据结构—基础知识(15):哈夫曼树

    哈夫曼(Huffman)树 又称最优树,是一类带权路径长度最短的树,在实际中有广泛的用途。哈夫曼树的定义,涉及路径、路径长度、权等概念,下面先给出这些概念的定义,然后再介绍哈夫曼树 路径 :从树中一个结点到另一个结点之间的分支构成这两个结点之间的路径。 路

    2024年02月19日
    浏览(15)
  • 数据结构—顺序表(如果想知道顺序表的全部基础知识点,那么只看这一篇就足够了!)

    数据结构—顺序表(如果想知道顺序表的全部基础知识点,那么只看这一篇就足够了!)

            前言:学习完了C语言的基础知识点之后,我们就需要使用我们所学的知识来进一步对存储在内存中的数据进行操作,这时候我们就需要学习数据结构。而这篇文章为数据结构中顺序表的讲解。 ✨✨✨ 这里是秋刀鱼不做梦的BLOG ✨✨✨ 想要了解更多内容可以访问我的

    2024年04月13日
    浏览(11)
  • Python爬虫|基础知识点详细汇总(requests、urllib、re、bs4、xpath、PyQuery、jsonpath、多线程、协程、数据保存、selenium)

    1. 请求数据 ① requests (1) 基本使用 参数 对响应内容的操作 (2) Requests进阶:使用Session 为什么要用 Session? Session代表服务器与浏览器的一次会话过程,Session对象存储了特定用户会话所需的信息 例如:一定时间内记录账号密码 (自动登录) 可以加快 requests请求速度 需要客户端登录的

    2023年04月08日
    浏览(13)
  • FPGA基础知识点

    FPGA基础知识点

    基础知识 逻辑值 逻辑0:表示低电平,也就是对应电路GND 逻辑1:表示高电平,也就是对应电路VCC 逻辑X:表示未知,有可能是高电平也有可能是低电平 逻辑Z:表示高阻态,外部没有激励信号,是一个悬空状态 数字进制格式 Verilog数字进制格式包括 二进制(b) , 八进制(

    2024年02月03日
    浏览(10)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包