Day15

一. Map集合

  1. 定义

    • Map集合是一个双列集合,以键值对的形式存在
    • 将键和值捆绑到一起存放(Map.Entry)
    • 一个映射不能包含重复的键
    • 如果出现相同的键,会用新的值覆盖老的值
    • 每个键最多只能映射到一个值
  2. Map接口和Collection接口的不同

    • Map是双列的,Collection是单列的
    • Map集合的数据结构针对键有效, 跟值无关, Collection 集合的数据结构是针对元素有效
  3. 常用功能

    • 添加方法
      • V put(K key , V value): 添加元素
        • 如果键是第一次存储, 直接存储元素,返回null
        • 如果键不是第一个存在, 就用值把以前的值替换掉,返回以前的值
    • 删除方法
      • void clear() : 移除所有的键值对元素
      • V remove(Object key) : 根据键删除键值对元素, 并把值返回
    • 判断方法
      • boolean containsKey(Object key) : 判断集合是否包含指定的键
      • boolean containsValue(Object value): 判断集合是否包含指定的值
      • boolean isEmpty: 判断集合是否为空
    • 获取方法
      • Set<Map.Entry<K,V>> entrySet() : 获取所有的键值对
      • V get(Object key) : 根据键获取值
      • Set<K> keySet() : 获取集合中所有键的集合
      • Collection<V> values() : 获取集合中所有值的集合
      • int size() : 返回集合中键值对的个数
  4. 演示

    public static void main(String[] args) {
     Map<String, Integer> map = new HashMap<>();
     
     //添加方法
     map.put("小红", 18);
     map.put("小明", 24);
     map.put("小辉", 26);
     map.put("小李", 19);
     map.put("小王", 18);
     System.out.println(map);
     
     //判断键是否存在
     boolean flg = map.containsKey("小红");
     System.out.println(flg);
     //判断值是否存在
     flg = map.containsValue(18);
     System.out.println(flg);
     //判断集合是否为空
     flg = map.isEmpty();
     System.out.println(flg);
     //根据键获取值
     Integer i = map.get("小王");
     System.out.println(i);
     //获取集合中元素的个数
     int size = map.size();
     System.out.println(size);
     //获取集合中所有的键值对
     Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
     System.out.println(entrySet);
     //获取集合中所有键
     Set<String> keyset = map.keySet();
     System.out.println(keyset);
     //获取集合中所有的值
     Collection<Integer> valueSet = map.values();
     System.out.println(valueSet);
     
    }
    

二. Map集合的遍历

  1. 获取所有键的集合的遍历

    • 通过keySet方法获取到所有键的Set集合
    • 演示
    public static void main(String[] args) {
     Map<String, Integer> map = new HashMap<>();
     
     map.put("小红", 18);
     map.put("小明", 24);
     map.put("小辉", 26);
     map.put("小李", 19);
     map.put("小王", 18);
     
     Set<String> keyset = map.keySet();
     Iterator<String> it = keyset.iterator();
     while (it.hasNext()) {
         String key = it.next();
         Integer value = map.get(key);
         System.out.println("键:"+key+" 值:"+value);
     }
    }
    
  2. 获取所有的值的遍历

    • 通过values方法获取所有值的Collection集合
    • 演示
    public static void main(String[] args) {
     Map<String, Integer> map = new HashMap<>();
     
     map.put("小红", 18);
     map.put("小明", 24);
     map.put("小辉", 26);
     map.put("小李", 19);
     map.put("小王", 18);
     
     Collection<Integer> values = map.values();
     Iterator<Integer> it = values.iterator();
     while (it.hasNext()) {
         Integer value = it.next();
         System.out.println("值:"+value);
     }
    }
    
  3. 获取所有键值对的遍历

    • 通过entrySet集合获取所有的键值对的Set集合
    • 演示
    public static void main(String[] args) {
     Map<String, Integer> map = new HashMap<>();
     
     map.put("小红", 18);
     map.put("小明", 24);
     map.put("小辉", 26);
     map.put("小李", 19);
     map.put("小王", 18);
     
     Set<Entry<String, Integer>> entrySet = map.entrySet();
     Iterator<Entry<String, Integer>> it = entrySet.iterator();
     while (it.hasNext()) {
         Map.Entry<String,Integer> entry = it.next();
         String key = entry.getKey();
         Integer value = entry.getValue();
         System.out.println("键:"+key+" 值:"+value);
     }
    }
    

三. HashMap

  1. 定义

    • 底层使用的是数组
    • HashMap就是通过我们存入的key获取到一个hash值, 经过计算之后, 获取到一个数组角标, 然后将key和value封装到一个Entry里面, 然后存入数组
    • 当数组容量不够的时候, 会自动扩容一倍
  1. 构造方法

    • HashMap()
      • 构造一个具有默认初始容量(16) 和默认加载因子(0.75)的空HashMap
    • HashMap(int initialCapacity)
      • 构造一个带指定初始容量和默认加载因子 (0.75) 的空HashMap
    • HashMap(int initialCapacity, float loadFactor)
      • 构造一个带指定初始容量和加载因子的空HashMap
    • HashMap(Map<? extends K, ?extends V> m)
      • 构造一个映射关系与制定Map相同的新HashMap
  2. 常用方法

    • put(K key, V value) : 在此映射中关联指定值与指定键
    • putAll(Map<? extends K, ?extends V> m) : 将另外一个map集合复制到此集合中
  3. 案例

    • HashMap集合键是Student值是String的案例
    • 注意
      • 如果我们需要将对象中的内容当作比较依据的话, 就必须要重写hashCode和equals方法
    • 演示
    public static void main(String[] args) {
     Map<Student, String> map = new HashMap<>();
     
     map.put(new Student("小红", 18), "美女");
     map.put(new Student("小李", 18), "老板的小舅子");
     
     for (Entry<Student, String> entry : map.entrySet()) {
         System.out.println(entry.getKey()+"::"+entry.getValue());
     }
    }
    
  4. 测试题

    • 需求: 从键盘录入一串字符, 统计字符串中每个字符出现的次数
    • 演示
    public static void main(String[] args) {
    
     Scanner scanner = new Scanner(System.in);
     
     String str = scanner.nextLine();
     
     HashMap<Character, Integer> hm = new HashMap<>();;
     
     for (int i = 0; i < str.length(); i++) {
         char ch = str.charAt(i);
         if(hm.get(ch)==null)
             hm.put(ch, 1);
         else
             hm.put(ch, hm.get(ch)+1);
     }
     System.out.println(hm);
     scanner.close();
    }
    

四. HashMap和Hashtable的区别

  1. HashMap和Hashtable的区别

    • Hashtable是JDK1.0版本出现的,是线程安全的,效率低,HashMap是JDK1.2版本出现的,是线程不安全的,效率高
    • Hashtable不可以存储null键和null值,HashMap可以存储null键和null值
  2. 案例演示

    public static void main(String[] args) {
     Map<String, String> map = new HashMap<>();
    
     map.put("小红", "美女");
     map.put("小李", "老板的小舅子");
     map.put(null, null);
     
     Hashtable<String, String> table = new Hashtable<>();
     table.put("小红", "美女");
     //table.put(null, null);//会报错
    }
    

五. TreeMap

  1. 定义

    • TreeMap通过比较元素的大小,对元素进行排序, 最后形成了一个树状结构
    • TreeMap中的key需要实现Comparable接口并重写compareTo方法, 或者使用Comparator比较器
    • 存入元素的时候,如果会将新添加的元素的key和集合中已经存在的元素的key比较,返回一个小于0的数,说明,新添加的元素小于已有元素, 如果返回的是一个等于0的数,说明新添加的元素等于已有元素, value覆盖, 如果返回一个大于0的数,说明新添加的元素大于已有元素
  2. 案例演示

    public static void main(String[] args) {
    
     Map<String, String> map2 = new TreeMap<>();
     map2.put("小红", "美女");
     map2.put("小红", "老板的小舅子");
     System.out.println(map2);
    }
    

六. 案例(模拟洗牌和发牌)

  1. 演示

    public static void main(String[] args) {
     String[] num = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
     String[] color = {"方片","梅花","红桃","黑桃"};
     ArrayList<String> poker = new ArrayList<>();
    
     for(String s1 : color) {
         for(String s2 : num) {
             poker.add(s1.concat(s2));
         }
     }
    
     poker.add("小王");
     poker.add("大王");
     
     Random random = new Random();
     int count = poker.size();
     for (int i = 0; i < count; i++) {
         int index1 = random.nextInt(count);
         int index2 = random.nextInt(count);
         Collections.swap(poker, index1, index2);
     }
     
     List<String> one = new ArrayList<>();
     List<String> two = new ArrayList<>();
     List<String> three = new ArrayList<>();
     List<String> dipai = new ArrayList<>();
     
     /*发牌*/
     for (int i = 0; i < poker.size(); i++) {
         //最后三张留作底牌
         if(i>=poker.size()-3)
             dipai.add(poker.get(i));
         else if(i%3==0)             //其他三个人依次发牌
             one.add(poker.get(i));
         else if(i%3==1)
             two.add(poker.get(i));
         else
             three.add(poker.get(i));
     }
     
     System.out.println(one);
     System.out.println(two);
     System.out.println(three);
     System.out.println(dipai);
    }
    

七. 泛型

  1. 定义

    • 泛型, 即"参数化类型" , 泛型规定了类可以使用的应用数据的类型的范围
    • 泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)
    • 只在编译期生效
  2. 泛型的好处

    • 提高安全性(将运行期的错误转换到编译期)
    • 省去强转的麻烦
    • 在其作用域内可以统一参数类型
  3. 泛型的基本使用

    • <>中放的必须是引用数据类型
    • 泛型可以定义来类上和方法上
  4. 泛型使用注意事项

    • 前后的泛型必须一致,或者后面的泛型可以省略不写(1.7的新特性菱形泛型)
  5. 泛型的由来

    • 类型通过Object 转型问题引入
    • 早期的Object类型可以接收任意的对象类型,但是在实际的使用中,会有类型转换的问题。也就存在这隐患,所以Java提供了泛型来解决这个安全问题。
    public class Generic {
     
     private Object object;
    
     public Object getObject() {
         return object;
     }
    
     public void setObject(Object object) {
         this.object = object;
     }
    }
    

八. 泛型的使用

  1. 把泛型定义在类上

    • 格式

      • public class 类名<泛型类型1,…>
    • 注意事项

      • 泛型类型必须是引用类型
    • 演示

      public class Generic<T> {
         
         private T t;
      
         public Object getObject() {
             return t;
         }
      
         public void setObject(T t) {
             this.t = t;
         }
      }
      
  2. 把泛型定义在方法上

    • 格式

      • public <泛型类型> 返回类型 方法名(泛型类型 变量名)
    • 演示

      public <E> E method(E[] e){
         
         return e[e.length/2];
      }
      
  3. 把泛型定义在接口上

    • 格式
      • public interface 接口名<泛型类型>
      • 子类去实现接口的时候就需要给出具体的类型, 重写抽象方法的时候就可以得到具体的类型
    • 演示
    public interface Inteface<T> {
     
     public void method(T t);
    }
    
  4. 通配符(了解)

    • 泛型通配符<?>

      • 任意类型,如果没有明确,那么就是Object以及任意的Java类了
      public static void main(String[] args) {
         ArrayList<String> arrayList1 = new ArrayList<>();
         
         ArrayList<Integer> arrayList2 = new ArrayList<>();
         
         List<?> list = arrayList1;
         list = arrayList2;
      }
      
    • ? extends E

      • 向下限定 E 及E的子类
    • ? super E

      • 向上限定 E及其父类

总结

  1. Map集合

    • 双列集合 一次性存两个值(key-value)
    • key-value : 键值对 映射
    • 特性:
      • key不能重复, value可以重复
  2. Map集合的方法

    • map集合的方法都是用来操作key的

    • put(key)

    • remove(key) clear

    • get(key)

  3. map集合的遍历

    • map集合没有自身的遍历方法, 要先转成set
    • keySet():获取所有的key
    • values() : 获取所有的value
    • entrySet() : 获取所有的键值对
  4. HashMap

    • 底层是数组
    • 存储时,通过key算出一个角标值, 如果当前位置上有元素, 就比较一下
      • 如果对比成功, 覆盖值
      • 如果没有成功, 挂载
    • 如果当前位置上没有元素, 直接存储
    • hashMap是如何判断是否重复的 key的地址值和hashCode和equals方法
  5. TreeMap

    • 底层是红黑树(二叉树)
    • key可以排序
    • 新元素要和老元素比较, 根据返回的结果判断存储的位置
      • 参考TreeSet
  6. HashSet和TreeSet底层用的HashMap和TreeMap

    • 其实就是将Set集合的元素当成Map集合的key
  7. 泛型

    • 设一个不是具体类型的类型
    • 好处
      • 提高代码的兼容性
      • 提高安全性,将运行期的错误提前到编译期
      • 省去强转的麻烦
      • 在一定范围统一类型
    • 泛型可以定义的地方
      • 接口, 类, 方法

作业

  1. 第一题
    • 需求:
      • 封装一个汽车类,包含String name、int speed属性,在测试类中实例化三个对象:c1,c2,c3,分别设置name为:“奥拓”,“宝马”,“奔驰”,速度分别设置为:100,200,300
      • 使用Map集合对象m1将这三个汽车类对象保存成key,然后将int型的汽车价钱作为值保存在m1的value中,上述三款汽车分别对应的价钱是10000,500000,2000000
    • 解题
      • 遍历m1的键,打印name属性
      • 通过合适的方法,求出m1中“宝马”的价格,并打印结果
      • 经过降速,所有汽车都降速到原来的80%,请打印降速后“宝马”的速度
  2. 第二题
    • 需求: 创建俩个List集合,添加一些数据,求它们的并集,差集和交集。
  3. 扩展题
    1. 第一题
      • 需求: 从键盘录入整数, 打印输入频率最高的整数, 如果有多个,就打印多个
    2. 第二题
      • 需求: 模拟斗地主洗牌发牌,并对已发好的拍进行排序(红桃A,方块A, 黑桃2.......)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,490评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,581评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,830评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,957评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,974评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,754评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,464评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,847评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,995评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,137评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,819评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,482评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,023评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,149评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,409评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,086评论 2 355

推荐阅读更多精彩内容