1: java.util.Map接口常用的方法
- Map和Collection没有继承关系
- Map集合以key和value的方式存储数据:键值对
- key和value都是引用数据类型
- key和value都是存储对象的内存地址
- key起到主导的地位,value是key的一个附属品
常用方法:
- V put(K key, V value):向Map集合中添加键值对
- *void clear():清空Map集合
- boolean containsKey(Object key):判断是否包含某个key
- boolean containsValue(Object value):判断是否包含某个value
- V get(Object key):通过Key获取Value
- boolean isEmpty()*:判断Map集合中元素个数是否为0
- Set keySet():获取Map集合中所有的key
- *V remove(Object key):通过key删除键值对
- int size():获取Map集合中键值对的个数
- Collection values():获取Map集合中所有的value,返回一个Collection
- Set<Map.Entry<K,V>> entrySet()*:将Map集合转换成set集合
![在这里插入图片描述](
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class MapTest01 {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
map.put(1,"zhangsan");//自动装箱
map.put(2,"lisi");
map.put(3,"lisi2");
map.put(4,"lisi3");
//通过key获取value
String value = map.get(2);
System.out.println(value);
//获取所有的value
Collection<String > values = map.values();
for(String s:values){
System.out.println(s);
}
//获取键值对的数量
System.out.println(map.size());
//通过key删除key-value
map.remove(2);
System.out.println("键值对的数量:"+map.size());
//判断是否包含某个key
System.out.println(map.containsKey(4));//底层调用equals,所以自定义类型需要重写equals方法
//判断是否包含某个value
System.out.println(map.containsValue("zhangsan"));//底层调用equals
//清空map集合
map.clear();
//判断是否为空
map.isEmpty();
}
}
2. Map集合的遍历
方式一: 通过key获取value
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapTest02 {
public static void main(String[] args) {
//第一种方式,获取所有的key,通过遍历key来获取value
Map<Integer,String> map = new HashMap();
map.put(1,"zhangsan");
map.put(2,"lisi");
map.put(3,"wangwu");
map.put(4,"zhaoliu");
//遍历集合
// 先获取所有的key,所有的key是一个set集合
Set<Integer> keys = map.keySet();
//迭代器
Iterator<Integer> it = keys.iterator();
while (it.hasNext()){
Integer key = it.next();
String value = map.get(key);
System.out.println(key+"="+value);
}
//foreach
for(Integer key:keys){
System.out.println("通过foreach获取");
System.out.println(map.get(key));
}
}
}
方式二 Set<Map.Entry<k,v>> entrySet()
原理:
//Set集合中元素的类型是:Map.entry
Set<Map.Entry<Integer,String>> set = map.entrySet();
//迭代器
//遍历set集合,每次取出一个Node
Iterator<Map.Entry<Integer,String>> it = set.iterator();
while (it.hasNext()){
Map.Entry<Integer,String> node = it.next();
Integer key = node.getKey();
String value = node.getValue();
System.out.println(key+"="+value);
}
//foreach(适合大数据量的情况,效率比较高,因为获取key和value都是从node直接获取)
for(Map.Entry<Integer, String> node:set){
System.out.println(node.getKey()+">>>"+node.getValue());
}
3. HashMap集合
- 是哈希表(散列表)的数据结构
哈希表是一个数组和单向链表的结合体
数组:在查询方面效率较高,随机增删方面效率很低
单向链表:在查方面效率很高,随机增删方面效率很低
哈希表将以上两种数据结构融合在一起,充分发挥它们各自的优点
掌握Map中元素的存取原理:
重点:HashMap集合的key会先后调用两个方法,一个方法是hashCode(),一个方法是equals(),那么这两个方法都需要重写。
HashMap集合key的部分特点:
无序:因为不一定挂到哪个单链表上
不可重复:equals方法来保证HashMap集合的key不可重复,因为key重复了,value会被覆盖。
注意:
同一个单向链表上所有节点的hash相同,因为他们的数组下标是一样的。
但同一个链表上的k和k的equals方法肯定返回的都是false,都不相等。
哈希表使用不当是无法发挥性能:
- 如果将所有的hashCode()方法返回为某个固定的值,那么会导致底层哈希表变成了纯单向链表。这种情况称为:散列分布不均匀。
- 如果将所有的hashcode()方法的返回值都设定为不一样的值,那么会导致底层哈希表成了一位数组了,没有链表的概念了。也是散列分布不均匀。
- 散列分布均匀需要在重写hashCode()时有一定的技巧。
重写hashCode()方法(重点)
- HashMap集合的默认初始化容量是16,默认加载因子是0.75
这个默认加载因子是当HashMap集合底层数组的容量达到75%的时候,数组开始扩容。
HashMap集合初始化容量必须是2的倍数,为了达到散列均匀,为了提高HashMap集合的存取效率。
-向Map集合中存,以及从Map集合中取,都是先调用key的hashCode方法,然后再调用equals方法。
equals方法有可能调用,也可能不调用。k.hashCode()方法返回哈希值。哈希值经过哈希算法转换成数组下标。数组下标位置上如果是null,equals不需要执行。
- 注意:如果一个类的equals方法重写了,那么hashCode()方法必须重写,并且equals方法返回如果是true(同一个单向链表上),hashCode()方法返回的值必须一样。
直接用IDEA工具生成的equals和hashCode方法重写
HashMap 集合key部分:允许为null,但是hashMap的key的null值只能有一个
4. Hashtable集合
不允许 key和value的值为null。
线程安全的,使用较少。
底层也是哈希表数据结构
初始化容量:11,默认加载因子:0.75,扩容之后是原容量的:*2+1
5. Properties
- Properties是一个Map集合,继承自Hashtable集合。
- key和value都是String类型
- 被称为属性类对象
- 是线程安全的
- 需要掌握2个方法:存和取
import java.util.Properties;
public class PropertiesTest01 {
public static void main(String[] args) {
Properties pro = new Properties();
// 存
pro.setProperty("url","jdbc:mysql://localhost:3306");
pro.setProperty("dirver","com.mysql.jdbc.Driver");
pro.setProperty("username","root");
pro.setProperty("password","123");
// 取
String url = pro.getProperty("url");
System.out.println(url);
}
}
6. TreeSet集合
- 底层是一个TreeMap
- TreeMap集合底层是一个二叉树
- 放到TreeSet集合中的元素等同于放到TreeMap集合中的key部分
- 无需不可重复,但是可以按照元素的大小顺序自动排序,可排序集合
对于自定义的类型,TreeSet不可以排序。需要指定对象之间的比较规则。
自定义类型实现comparable接口:
放在TreeSet集合中的元素需要实现java.lang.Comparable接口
并且实现compareTo方法。equals可以不写。
import java.util.TreeSet;
public class TreeSetTest04 {
public static void main(String[] args) {
Customerz c1 = new Customerz(32);
Customerz c2 = new Customerz(22);
Customerz c3 = new Customerz(62);
Customerz c4 = new Customerz(12);
TreeSet<Customerz> customers = new TreeSet();
customers.add(c1);
customers.add(c2);
customers.add(c3);
customers.add(c4);
for(Customerz c:customers){
System.out.println(c);
}
}
}
class Customerz implements Comparable<Customerz>{
int age;
public Customerz(int age){
this.age=age;
}
// 需要再这个方法中编写比较的逻辑,或者说比较的规则,按照什么比较!
// k.compareTo(t.key)
//拿着参数k和集合中的每一个k进行比较,返回值可能是 >0 <0 =0
//比较规则最终还是由程序员自己指定:例如按照年龄升序或者降序
@Override
public int compareTo(Customerz o) {//c1.compareTo(c2)
//this是c1
return this.age - o.age;
}
@Override
public String toString() {
return "Customerz{" +
"age=" + age +
'}';
}
}