14 Java集合(Map集合+HashMap+泛型使用+集合面试题)
创始人
2024-05-15 04:42:02
0

集合

      • 14.11 Map集合
        • 14.11.1 Map集合特点
        • 14.11.2 Map集合体系结构
      • 14.12 HashMap
        • 14.12.1 HashMap基本使用
        • 14.12.2 HashMap实际应用
        • 14.12.3 HashMap练习
        • 14.12.4 HashMap底层实现原理
        • 14.12.5 put的过程原码
        • 14.12.6 resize过程原码
        • 14.12.7 get的过程原码
      • 14.13 HashTable
      • 14.14 泛型高级使用
        • 14.14.1 泛型类
        • 14.14.2 泛型接口
        • 14.14.3 泛型方法
        • 14.14.4 泛型上下边界
      • 14.15 常见的集合面试面试题

``

14.11 Map集合

14.11.1 Map集合特点

  • Map集合是双列集合,由key和value组成。称之为键值对
  • 键的特点:无序,无下标,不重复。
  • 值的特点:无序,无下标,可重复

14.11.2 Map集合体系结构

Map集合体系结构
请添加图片描述

14.12 HashMap

14.12.1 HashMap基本使用

常用方法

  • put(K key, V value)
  • get(Object key)
  • Set keySet()
  • Collection values()
  • Set> entrySet()
  • boolean containsKey(Object key)
  • boolean containsValue(Object value)
  • V remove(Object key)
  • int size()
package com.qf.demo01;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;
public class HashMapDemo {public static void main(String[] args) {//创建HashMapHashMap map = new HashMap(12);//向map集合中添加元素map.put("usa", "漂亮国");map.put("jp", "日本");map.put("en", "英国");map.put("ca", "加拿大");map.put("cn", "中华人民共和国");map.put("cn", "中国");map.put("china", "中国");System.out.println(map);//从集合中获取元素的值。    根据key获取对应valueSystem.out.println(map.get("cn"));System.out.println(map.get("usa"));//清空map集合中的元素//map.clear();//System.out.println(map);//判断是否包含指定的keySystem.out.println(map.containsKey("xjp"));//判断是否包含指定的valueSystem.out.println(map.containsValue("中国"));//判断集合中的元素长度是否为0System.out.println(map.isEmpty());//根据key移除map中的元素map.remove("jp");System.out.println(map);//返回map集合中元素的个数System.out.println(map.size());		System.out.println("=================================");//返回map集合中所有的keySet keySet = map.keySet();for (String key : keySet) {System.out.println(key);}System.out.println("=================================");//返回map集合中所有的valueCollection values = map.values();for (String value : values) {System.out.println(value);}System.out.println("=================================");//返回map集合中所有的key和value (Entry)Set> entrySet = map.entrySet();for (Entry entry : entrySet) {System.out.println(entry.getKey());System.out.println(entry.getValue());}System.out.println("=================================");	}
}

14.12.2 HashMap实际应用

  • 可以使用Map 表示一个实体类
  • 可以使用List> 表示一个实体类集合
public class HashMapDemo02 {/*** 表示一件商品:商品编号、名称、价格、产地、上架时间....* * 实体类表示:*  一件商品:Product对象*      public class Product{*          private int id;*          private String name;*          private double price;*          .....*      }*      Product product = new Product(1,"手机",3000...);*      *  多件商品:List* * Map表示:* 	一件商品:Map对象* 		Map map = new HashMap<>();*      map.put("id",1);*      map.put("name","电脑");*      map.put("price",3000.5);* *  多件商品:List>*/public static void main(String[] args) {//使用Map表示一件商品Map map = new HashMap();map.put("id", 1);map.put("name", "电脑");map.put("price",3000.5);map.put("createDate", new Date());Map map1 = new HashMap();map1.put("id", 2);map1.put("name", "电脑2");map1.put("price",3002.5);map1.put("createDate", new Date());//使用List表示多件商品List> list = new ArrayList>();list.add(map);list.add(map1);for (Map map2 : list) {System.out.println(map2);}//使用集合实现存储省市信息}
}

14.12.3 HashMap练习

案例:使用集合保存省市数据

Map> map = new HashMap>();
List city1 = new ArrayList();
city1.add("武汉");
city1.add("监利");
city1.add("黄冈");
city1.add("荆州");
map.put("湖北省", city1);
List city2 = new ArrayList();
city2.add("长沙");
city2.add("岳阳");
city2.add("常德");
city2.add("湘潭");
map.put("湖南省", city2);
System.out.println(map.get("湖北省"));

14.12.4 HashMap底层实现原理

HashMap底层实现原理
请添加图片描述

14.12.5 put的过程原码

put流程
请添加图片描述
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {//tab表示存放Node节点的数据   p表示当前节点   n表示长度  i表示节点在数组中的下标			   Node[] tab; Node p; int n, i;//判断数组如果为空或者数组长度为0,那么就对数组进行扩容,数组默认初始大小为16if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;//将数组的长度-1与hash值进行与运算(计算的结果一定是0~数组长度-1)得到元素应该存放的下标//如果当前下标位置为空,那么直接将Node节点存放在当前位置if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);//如果当前位置不为空(分为三种情况)else {Node e; K k;//情况1:要添加的元素与当前位置上的元素相同(hash(hashCode)、key(equals)一致),则直接替换if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p;//情况2:如果要添加的元素是红黑树节点,那么将其添加到红黑树上else if (p instanceof TreeNode)e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);//情况3:如果要添加的元素是链表,则需要遍历else {for (int binCount = 0; ; ++binCount) {//将当前元素的下一个节点赋给e//如果e为空,则创建新的元素节点放在当前位置的下一个元素上,并退出循环if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);//如果链表的元素个数大于8个(且当数组中的元素个数大于64),则将其转换成红黑树if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);break;}//要添加的元素与当前位置上的元素相同(hash(hashCode)、key(equals)一致),则直接退出循环if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}//如果返回的e不为nullif (e != null) { // existing mapping for key//将e的值赋给oldValueV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);//返回以前的值(当添加的元素已经存在返回的是以前的值)return oldValue;}}++modCount;//如果数组的元素个数大于阈值则进行扩容if (++size > threshold)resize();afterNodeInsertion(evict);return null;
}

14.12.6 resize过程原码

扩容流程
请添加图片描述
final Node[] resize() {//oldTab 表示原来数组(如果是第二次扩容:长度为16的那个)Node[] oldTab = table;//oldCap 表示原数组的容量(长度)int oldCap = (oldTab == null) ? 0 : oldTab.length;//oldThr 表示数组原来的阈值 12int oldThr = threshold;//newCap 新数组的容量 newThr 新数组的阈值int newCap, newThr = 0;if (oldCap > 0) {if (oldCap >= MAXIMUM_CAPACITY) {threshold = Integer.MAX_VALUE;return oldTab;}//新数组的容量扩大一半  newCap 32else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&oldCap >= DEFAULT_INITIAL_CAPACITY)//新阈值扩大老阈值的一半  newThr 24newThr = oldThr << 1; // double threshold}else if (oldThr > 0) // initial capacity was placed in thresholdnewCap = oldThr;else {               // zero initial threshold signifies using defaultsnewCap = DEFAULT_INITIAL_CAPACITY;newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);}if (newThr == 0) {float ft = (float)newCap * loadFactor;newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?(int)ft : Integer.MAX_VALUE);}//threshold 24threshold = newThr;@SuppressWarnings({"rawtypes","unchecked"})//创建一个长度为32的数组Node[] newTab = (Node[])new Node[newCap];//table指向新数组table = newTab;if (oldTab != null) {//将原数组中的元素拷贝到新数组中for (int j = 0; j < oldCap; ++j) {Node e;//如果当前位置元素不为空if ((e = oldTab[j]) != null) {oldTab[j] = null;//情况1:当前位置上的下一个元素为空,则直接将这个元素拷贝到新数组中if (e.next == null)newTab[e.hash & (newCap - 1)] = e;	//情况2:当前位置上的元素红黑树类型,则需要进行切割else if (e instanceof TreeNode)((TreeNode)e).split(this, newTab, j, oldCap);//情况3:当前位置上的元素链表类型,则需要进行分散拷贝else { // preserve orderNode loHead = null, loTail = null;Node hiHead = null, hiTail = null;Node next;do {next = e.next;if ((e.hash & oldCap) == 0) {if (loTail == null)loHead = e;elseloTail.next = e;loTail = e;}else {if (hiTail == null)hiHead = e;elsehiTail.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;
}

14.12.7 get的过程原码

final Node getNode(int hash, Object key) {Node[] tab; Node first, e; int n; K k;if ((tab = table) != null && (n = tab.length) > 0 &&(first = tab[(n - 1) & hash]) != null) {//当前first与要找到的hash和key都相等直接返回当前这个first元素if (first.hash == hash && // always check first node((k = first.key) == key || (key != null && key.equals(k))))return first;//如果当前first不为空(有两种情况)if ((e = first.next) != null) {//当前位置是一个红黑树if (first instanceof TreeNode)//根据hash、key从红黑树上找到对应的元素return ((TreeNode)first).getTreeNode(hash, key);//当前位置是一个链表do {//循环进行比较直到找到向的hash和key的元素,并返回if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))return e;} while ((e = e.next) != null);}}//如果数组的为空、数组的长度为0、当前下标位置上的值为null,这三种情况都返回nullreturn null;
}

14.13 HashTable

Hashtable常用方法与HashMap一致

HashMap与Hashtable区别:

  • 1、Hashtable是线程安全的,HashMap是线程不安全的
  • 2、Hashtable中不允许存储null作为key和value,而HashMap可以

在实际开发中一般都是用HashMap。考虑线程安全使用ConCurrentHashMap

14.14 泛型高级使用

14.14.1 泛型类

泛型类 类名

public class Box {  //T:表示任意的java类型       E、K、Vprivate T data;public T getData() {return data;}public void setData(T data) {this.data = data;}
}

14.14.2 泛型接口

泛型接口 接口名

public interface MyInterface {public void show(T t);
}

14.14.3 泛型方法

泛型方法 public T 方法名(T t,…){}

//泛型可以作为参数,(必须得先定义   )
public  void m1(T t) {}

14.14.4 泛型上下边界

泛型上下边界

  • 语法:
    • 上边界 ? extends 类型
    • 下边界 ? super 类型
public class Demo01 {//? 表示不确定类型     此时的?表示Objectpublic static void test01(List list) {}/*** 定义泛型上边界* * */public static void test02(List list) {}/*** 定义泛型下边界* * */public static void test03(List list) {}public static  void test04(List> list) {}public static void main(String[] args) {List list1 = new ArrayList();List list2 = new ArrayList();List list3 = new ArrayList();List list4 = new ArrayList();test01(list1);test01(list2);test01(list3);test01(list4);//test02(list1);  //错误,方法定义泛型的上边界,泛型只能是Number及其Number子类test02(list2);test02(list3);//test02(list4);  //错误,方法定义泛型的上边界,泛型只能是Number及其Number子类 //test03(list1);  //错误,方法定义泛型的下边界,泛型只能是Number及其Number父类//test03(list2);test03(list3);test03(list4);test04(list1);test04(list2);//test04(list3);    //错误,方法定义泛型的上边界,泛型必须实现Comparable接口//test04(list4);      //错误,方法定义泛型的上边界,泛型必须实现Comparable接口}	
}
 

14.15 常见的集合面试面试题

  • 1、简述:ArrayList、LinkedList、Vector的区别
  • 2、简述:HashSet、TreeSet的去重原理
  • 3、ArrayList、LinkedList底层实现
  • 4、HashMap、HashTable的区别
  • 5、HashMap底层实现原理
  • 6、HashMap扩容机制
  • 7、HashMap的数组容量为什么是2的次方数
  • 8、HashMap的负载因子为什么是0.75
  • 9、HashMap添加元素的过程
  • 10、谈谈了解的数据结构

相关内容

热门资讯

电视安卓系统哪个品牌好,哪家品... 你有没有想过,家里的电视是不是该升级换代了呢?现在市面上电视品牌琳琅满目,各种操作系统也是让人眼花缭...
安卓会员管理系统怎么用,提升服... 你有没有想过,手机里那些你爱不释手的APP,背后其实有个强大的会员管理系统在默默支持呢?没错,就是那...
安卓系统软件使用技巧,解锁软件... 你有没有发现,用安卓手机的时候,总有一些小技巧能让你玩得更溜?别小看了这些小细节,它们可是能让你的手...
安卓系统提示音替换 你知道吗?手机里那个时不时响起的提示音,有时候真的能让人心情大好,有时候又让人抓狂不已。今天,就让我...
安卓开机不了系统更新 手机突然开不了机,系统更新还卡在那里,这可真是让人头疼的问题啊!你是不是也遇到了这种情况?别急,今天...
安卓系统中微信视频,安卓系统下... 你有没有发现,现在用手机聊天,视频通话简直成了标配!尤其是咱们安卓系统的小伙伴们,微信视频功能更是用...
安卓系统是服务器,服务器端的智... 你知道吗?在科技的世界里,安卓系统可是个超级明星呢!它不仅仅是个手机操作系统,竟然还能成为服务器的得...
pc电脑安卓系统下载软件,轻松... 你有没有想过,你的PC电脑上安装了安卓系统,是不是瞬间觉得世界都大不一样了呢?没错,就是那种“一机在...
电影院购票系统安卓,便捷观影新... 你有没有想过,在繁忙的生活中,一部好电影就像是一剂强心针,能瞬间让你放松心情?而我今天要和你分享的,...
安卓系统可以写程序? 你有没有想过,安卓系统竟然也能写程序呢?没错,你没听错!这个我们日常使用的智能手机操作系统,竟然有着...
安卓系统架构书籍推荐,权威书籍... 你有没有想过,想要深入了解安卓系统架构,却不知道从何下手?别急,今天我就要给你推荐几本超级实用的书籍...
安卓系统看到的炸弹,技术解析与... 安卓系统看到的炸弹——揭秘手机中的隐形威胁在数字化时代,智能手机已经成为我们生活中不可或缺的一部分。...
鸿蒙系统有安卓文件,畅享多平台... 你知道吗?最近在科技圈里,有个大新闻可是闹得沸沸扬扬的,那就是鸿蒙系统竟然有了安卓文件!是不是觉得有...
宝马安卓车机系统切换,驾驭未来... 你有没有发现,现在的汽车越来越智能了?尤其是那些豪华品牌,比如宝马,它们的内饰里那个大屏幕,简直就像...
p30退回安卓系统 你有没有听说最近P30的用户们都在忙活一件大事?没错,就是他们的手机要退回安卓系统啦!这可不是一个简...
oppoa57安卓原生系统,原... 你有没有发现,最近OPPO A57这款手机在安卓原生系统上的表现真是让人眼前一亮呢?今天,就让我带你...
安卓系统输入法联想,安卓系统输... 你有没有发现,手机上的输入法真的是个神奇的小助手呢?尤其是安卓系统的输入法,简直就是智能生活的点睛之...
怎么进入安卓刷机系统,安卓刷机... 亲爱的手机控们,你是否曾对安卓手机的刷机系统充满好奇?想要解锁手机潜能,体验全新的系统魅力?别急,今...
安卓系统程序有病毒 你知道吗?在这个数字化时代,手机已经成了我们生活中不可或缺的好伙伴。但是,你知道吗?即使是安卓系统,...
奥迪中控安卓系统下载,畅享智能... 你有没有发现,现在汽车的中控系统越来越智能了?尤其是奥迪这种豪华品牌,他们的中控系统简直就是科技与艺...