Map集合:(映射的数学解释)
设A、B是两个非空集合,如果存在一个法则f,使得对A中的每一个元素a,按法则f,在B中有唯一确定的元素b与之对应,则称f为从A到B的映射,记作f:A→B。
映射关系(两个集合):A集合和B集合:
TreeMap:采用红黑树算法,此时Map中的key会按照自然排序或定制排序进行排序,key也不允许重复。(key判断重复的标准:compareTo/compare的返回值是否为0)
LinkedHashMap:采用链表和哈希表算法,此时Map中的key会保证先后添加的顺序,key也不允许重复。(key判断重复的标准和HashMap中的key的标准相同)
一般的,我们定义Map,key都是用不可改变的类(String),把key作为value的唯一名称。
HashMap和TreeMap以及LinkedHashMap都是线程不安全的,但是性能极高。
解决方案:Map map = Collections.sysnchronizedMap(Map对象);
Hashtable类是线程安全的,但是性能较低。
哈希表算法:做等值查询最快;
数组结构算法:做范围查询最快->应用到索引上。
Set:单一元素集合,不允许元素重复,不记录元素添加顺序。(既要不重复,又要保证先后顺序:LinkeHashSet)
Set<String> set = new HashSet<>(list);//此时会消除重复的元素
设A、B是两个非空集合,如果存在一个法则f,使得对A中的每一个元素a,按法则f,在B中有唯一确定的元素b与之对应,则称f为从A到B的映射,记作f:A→B。
映射关系(两个集合):A集合和B集合:
A集合中的每一个元素都可以在B集合中找到唯一的一个值与之对应。
因为Map接口并没有继承于Collection接口,也没有继承于Iterable接口,所以不能直接对Map使用for:each操作。但是可以间接迭代:
public class MapDemo {
public static void main(String[] args) {
Map<String, Object> map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
map.put("key4", "value4");
map.put("key5", "value5");
//Map不是集合,不能直接做迭代,但是可以间接做迭代,获取Map中所有的Key所组成的集合(key是不能重复,类似Set)
Set<String> set = map.keySet();
for (String key : set) {
System.out.println(key+"->"+map.get(key));
}
System.out.println("--------------------------");
//获取map中所有value所组成的集合(value是可以重复的,类似于List)
Collection<Object> value = map.values();
for (Object val : value) {
System.out.println(val);
}
System.out.println("--------------------------");
//获取map中所有的Entry(key->value)
Set<Map.Entry<String, Object>> entrys = map.entrySet();
for (Map.Entry<String, Object> entry : entrys) {
String key = entry.getKey(); //获取key
Object val = entry.getValue(); //获取value
System.out.println(key+"->"+val);
}
}
}
Map的常用实现类:
TreeMap:采用红黑树算法,此时Map中的key会按照自然排序或定制排序进行排序,key也不允许重复。(key判断重复的标准:compareTo/compare的返回值是否为0)
LinkedHashMap:采用链表和哈希表算法,此时Map中的key会保证先后添加的顺序,key也不允许重复。(key判断重复的标准和HashMap中的key的标准相同)
Hashtable:采用哈希表算法,是HashMap的前身。(类似Vector是ArrayList的前身)
在Java的集合框架之前,表示映射关系就是用Hashtable,所有的方法都是用synchronized修饰符,线程安全,但是性能相对HashMap较低
Properties:Hashtable的子类,此时要求key和value都是String类型。
一般的,我们定义Map,key都是用不可改变的类(String),把key作为value的唯一名称。
HashMap和TreeMap以及LinkedHashMap都是线程不安全的,但是性能极高。
解决方案:Map map = Collections.sysnchronizedMap(Map对象);
Hashtable类是线程安全的,但是性能较低。
哈希表算法:做等值查询最快;
数组结构算法:做范围查询最快->应用到索引上。
来看看一个很有意思的Map案例:计算一个字符串中,每个字符的出现次数:
public class MapStringDemo {
public static void main(String[] args) {
String str = "asdhlkadsjfhoifhlaksjbvoiuhdf";
//把字符串转换为char数组(字符串本质就是char[])
char[] arr = str.toCharArray();
//key:存储字符名,value:存储出现次数
Map<Character,Integer> map = new TreeMap<>();
//循环得到每一个字符串
for (char ch : arr) {
//判断当前字符是否在Map中的key存在
if(map.containsKey(ch)){
//当前Map的key包含该字符,此时取出该value值递增1,再放进去
Integer old = map.get(ch);
map.put(ch, old+1);
}else{
//当前Map的key不包含该字符,把该字符存储到Map只能怪,设置value为1
map.put(ch, 1);
}
}
System.out.println(map);
}
}
运行结果:
选用哪一种容器取决于每一种容器的存储特点以及当前业务的需求:
List:单一元素集合,允许元素重复,记录元素添加顺序。Set:单一元素集合,不允许元素重复,不记录元素添加顺序。(既要不重复,又要保证先后顺序:LinkeHashSet)
Map:双元素集合,如果存储数据的时候,还得给数据取唯一的每一个名称,此时考虑使用Map。
List<String> list = new ArrayList<>();
把List装换为Set:Set<String> set = new HashSet<>(list);//此时会消除重复的元素
把Set装换为List:
List<String> list = new ArrayList<>(set);
Map不能直接转换为List或Set(但是Map中的方法可以间接转换)。