一. Map集合
-
定义
- Map集合是一个双列集合,以键值对的形式存在
- 将键和值捆绑到一起存放(Map.Entry)
- 一个映射不能包含重复的键
- 如果出现相同的键,会用新的值覆盖老的值
- 每个键最多只能映射到一个值
-
Map接口和Collection接口的不同
- Map是双列的,Collection是单列的
- Map集合的数据结构针对键有效, 跟值无关, Collection 集合的数据结构是针对元素有效
-
常用功能
- 添加方法
- V put(K key , V value): 添加元素
- 如果键是第一次存储, 直接存储元素,返回null
- 如果键不是第一个存在, 就用值把以前的值替换掉,返回以前的值
- V put(K key , V value): 添加元素
- 删除方法
- void clear() : 移除所有的键值对元素
- V remove(Object key) : 根据键删除键值对元素, 并把值返回
- 判断方法
- boolean containsKey(Object key) : 判断集合是否包含指定的键
- boolean containsValue(Object value): 判断集合是否包含指定的值
- boolean isEmpty: 判断集合是否为空
- 获取方法
- Set
> entrySet() : 获取所有的键值对 - V get(Object key) : 根据键获取值
- Set
keySet() : 获取集合中所有键的集合 - Collection
values() : 获取集合中所有值的集合 - int size() : 返回集合中键值对的个数
- Set
- 添加方法
-
演示
public static void main(String[] args) { Map
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 > entrySet = map.entrySet(); System.out.println(entrySet); //获取集合中所有键 Set keyset = map.keySet(); System.out.println(keyset); //获取集合中所有的值 Collection valueSet = map.values(); System.out.println(valueSet); }
二. Map集合的遍历
-
获取所有键的集合的遍历
- 通过keySet方法获取到所有键的Set集合
- 演示
public static void main(String[] args) { Map
map = new HashMap<>(); map.put("小红", 18); map.put("小明", 24); map.put("小辉", 26); map.put("小李", 19); map.put("小王", 18); Set keyset = map.keySet(); Iterator it = keyset.iterator(); while (it.hasNext()) { String key = it.next(); Integer value = map.get(key); System.out.println("键:"+key+" 值:"+value); } } -
获取所有的值的遍历
- 通过values方法获取所有值的Collection集合
- 演示
public static void main(String[] args) { Map
map = new HashMap<>(); map.put("小红", 18); map.put("小明", 24); map.put("小辉", 26); map.put("小李", 19); map.put("小王", 18); Collection values = map.values(); Iterator it = values.iterator(); while (it.hasNext()) { Integer value = it.next(); System.out.println("值:"+value); } } -
获取所有键值对的遍历
- 通过entrySet集合获取所有的键值对的Set集合
- 演示
public static void main(String[] args) { Map
map = new HashMap<>(); map.put("小红", 18); map.put("小明", 24); map.put("小辉", 26); map.put("小李", 19); map.put("小王", 18); Set > entrySet = map.entrySet(); Iterator > it = entrySet.iterator(); while (it.hasNext()) { Map.Entry entry = it.next(); String key = entry.getKey(); Integer value = entry.getValue(); System.out.println("键:"+key+" 值:"+value); } }
三. HashMap
-
定义
- 底层使用的是数组
- HashMap就是通过我们存入的key获取到一个hash值, 经过计算之后, 获取到一个数组角标, 然后将key和value封装到一个Entry里面, 然后存入数组
- 当数组容量不够的时候, 会自动扩容一倍
-
构造方法
- 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
- HashMap()
-
常用方法
- put(K key, V value) : 在此映射中关联指定值与指定键
- putAll(Map extends K, ?extends V> m) : 将另外一个map集合复制到此集合中
-
案例
- HashMap集合键是Student值是String的案例
- 注意
- 如果我们需要将对象中的内容当作比较依据的话, 就必须要重写hashCode和equals方法
- 演示
public static void main(String[] args) { Map
map = new HashMap<>(); map.put(new Student("小红", 18), "美女"); map.put(new Student("小李", 18), "老板的小舅子"); for (Entry entry : map.entrySet()) { System.out.println(entry.getKey()+"::"+entry.getValue()); } } -
测试题
- 需求: 从键盘录入一串字符, 统计字符串中每个字符出现的次数
- 演示
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String str = scanner.nextLine(); HashMap
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的区别
-
HashMap和Hashtable的区别
- Hashtable是JDK1.0版本出现的,是线程安全的,效率低,HashMap是JDK1.2版本出现的,是线程不安全的,效率高
- Hashtable不可以存储null键和null值,HashMap可以存储null键和null值
-
案例演示
public static void main(String[] args) { Map
map = new HashMap<>(); map.put("小红", "美女"); map.put("小李", "老板的小舅子"); map.put(null, null); Hashtable table = new Hashtable<>(); table.put("小红", "美女"); //table.put(null, null);//会报错 }
五. TreeMap
-
定义
- TreeMap通过比较元素的大小,对元素进行排序, 最后形成了一个树状结构
- TreeMap中的key需要实现Comparable接口并重写compareTo方法, 或者使用Comparator比较器
- 存入元素的时候,如果会将新添加的元素的key和集合中已经存在的元素的key比较,返回一个小于0的数,说明,新添加的元素小于已有元素, 如果返回的是一个等于0的数,说明新添加的元素等于已有元素, value覆盖, 如果返回一个大于0的数,说明新添加的元素大于已有元素
-
案例演示
public static void main(String[] args) { Map
map2 = new TreeMap<>(); map2.put("小红", "美女"); map2.put("小红", "老板的小舅子"); System.out.println(map2); }
六. 案例(模拟洗牌和发牌)
-
演示
public static void main(String[] args) { String[] num = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"}; String[] color = {"方片","梅花","红桃","黑桃"}; ArrayList
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 one = new ArrayList<>(); List two = new ArrayList<>(); List three = new ArrayList<>(); List 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.7的新特性菱形泛型)
-
泛型的由来
- 类型通过Object 转型问题引入
- 早期的Object类型可以接收任意的对象类型,但是在实际的使用中,会有类型转换的问题。也就存在这隐患,所以Java提供了泛型来解决这个安全问题。
public class Generic { private Object object; public Object getObject() { return object; } public void setObject(Object object) { this.object = object; } }
八. 泛型的使用
-
把泛型定义在类上
-
格式
- public class 类名<泛型类型1,…>
-
注意事项
- 泛型类型必须是引用类型
-
演示
public class Generic
{ private T t; public Object getObject() { return t; } public void setObject(T t) { this.t = t; } }
-
-
把泛型定义在方法上
-
格式
- public <泛型类型> 返回类型 方法名(泛型类型 变量名)
-
演示
public
E method(E[] e){ return e[e.length/2]; }
-
-
把泛型定义在接口上
- 格式
- public interface 接口名<泛型类型>
- 子类去实现接口的时候就需要给出具体的类型, 重写抽象方法的时候就可以得到具体的类型
- 演示
public interface Inteface
{ public void method(T t); } - 格式
-
通配符(了解)
-
泛型通配符>
- 任意类型,如果没有明确,那么就是Object以及任意的Java类了
public static void main(String[] args) { ArrayList
arrayList1 = new ArrayList<>(); ArrayList arrayList2 = new ArrayList<>(); List> list = arrayList1; list = arrayList2; } -
? extends E
- 向下限定 E 及E的子类
-
? super E
- 向上限定 E及其父类
-
总结
-
Map集合
- 双列集合 一次性存两个值(key-value)
- key-value : 键值对 映射
- 特性:
- key不能重复, value可以重复
-
Map集合的方法
map集合的方法都是用来操作key的
put(key)
remove(key) clear
get(key)
-
map集合的遍历
- map集合没有自身的遍历方法, 要先转成set
- keySet():获取所有的key
- values() : 获取所有的value
- entrySet() : 获取所有的键值对
-
HashMap
- 底层是数组
- 存储时,通过key算出一个角标值, 如果当前位置上有元素, 就比较一下
- 如果对比成功, 覆盖值
- 如果没有成功, 挂载
- 如果当前位置上没有元素, 直接存储
- hashMap是如何判断是否重复的 key的地址值和hashCode和equals方法
-
TreeMap
- 底层是红黑树(二叉树)
- key可以排序
- 新元素要和老元素比较, 根据返回的结果判断存储的位置
- 参考TreeSet
-
HashSet和TreeSet底层用的HashMap和TreeMap
- 其实就是将Set集合的元素当成Map集合的key
-
泛型
- 设一个不是具体类型的类型
- 好处
- 提高代码的兼容性
- 提高安全性,将运行期的错误提前到编译期
- 省去强转的麻烦
- 在一定范围统一类型
- 泛型可以定义的地方
- 接口, 类, 方法
作业
- 第一题
- 需求:
- 封装一个汽车类,包含String name、int speed属性,在测试类中实例化三个对象:c1,c2,c3,分别设置name为:“奥拓”,“宝马”,“奔驰”,速度分别设置为:100,200,300
- 使用Map集合对象m1将这三个汽车类对象保存成key,然后将int型的汽车价钱作为值保存在m1的value中,上述三款汽车分别对应的价钱是10000,500000,2000000
- 解题
- 遍历m1的键,打印name属性
- 通过合适的方法,求出m1中“宝马”的价格,并打印结果
- 经过降速,所有汽车都降速到原来的80%,请打印降速后“宝马”的速度
- 需求:
- 第二题
- 需求: 创建俩个List集合,添加一些数据,求它们的并集,差集和交集。
- 扩展题
- 第一题
- 需求: 从键盘录入整数, 打印输入频率最高的整数, 如果有多个,就打印多个
- 第二题
- 需求: 模拟斗地主洗牌发牌,并对已发好的拍进行排序(红桃A,方块A, 黑桃2.......)
- 第一题