Map接口是一种双列集合,它的元素都包含一个键对象Key和值对象Value,键和值对象之间存在一种对应关系,称为映射,而且是一对一映射。
Map结构的理解:
一.HashMap集合① Map中的Key:无序的、不可重复,使用Set存储所有的Key—> Key所在的类要重写equals()和hashcode()(以HashMap为例)
② Map中的Value:无序的、可重复,使用Collection存储所有的Value—>Value所在的类要重写equals()
③ 一个键值对: key-value构成了一个Entry对象。
④ Map中的Entry:无序的、不可重复,使用Set存储所有的Entry
HashMap作为Map的主要实现类,元素无序,增删改查效率高,线程不安全,存储的键和值允许为null,键不能重复,值可以重复(类似于中学的函数)。
1.HashMap底层:
数组+链表(jdk 7及以前)
数组+链表+红黑树(jdk 8及以后)
2.HashMap存储流程:
以jdk 7为例,执行HashMap map = new HashMap();以后,底层创建了长度是16的一维数组Entry[] table。执行map.put(key,value)添加元素,当执行map.put( key1, value1 )时。首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置。如果此位置上的数据为空,此时的key1-value1添加成功。----情况1
如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表形式存在)),比较key1和已经存在的一个或多个数据的哈希值:如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功。----情况2
如果key1的哈希值和已经存在的某一个数据(key2-vaLue2)的哈希值相同,继续比较:调用key1所在类的equals(key2)
如果equals()返回false:此时key1-value1添加成功。—-情况3
如果equals()返回true:使用value1替换value2.
情况2和情况3时,此时的key1-value1和之前的使用链表存储(七上八下,八下:原先元素指向被添加元素);在不断添加元素的过程中,超过临界值(0.75*16=12)时并未且存放的位置为null时,扩容为原来的2倍,并将原先的数据复制过来。
3.HashMap在Jdk 8相较于Jdk 7在底层实现方面的不同:
① new HashMap()∶底层没有创建一个长度为16的数组;②首次调用put()方法时,底层创建长度为16的数组; ③ Jdk 8底层的数组是:Node[],而非Entry[];④ Jdk7底层结构只有:数组+链表;Jdk8中底层结构:数组+链表+红黑树。当数组的某一个索引位置上的元素以链表形式存在的数据个数>8,且当前数组的长度>64时此时此索引位置上的所有数据改为使用红黑树存储。
//Map集合常用方法 @Test public void test01(){ Map hashMap = new HashMap(); //1.void put(Object key,Object value):添加元素 hashMap.put(100,"Tom"); hashMap.put(101,"Jack"); hashMap.put(false,25); hashMap.put('A',"小王"); System.out.println(hashMap);//{A=小王, 100=Tom, 101=Jack, false=25} //2.void put(Object key,Object value):修改元素 hashMap.put(100,"Marry"); System.out.println(hashMap);//{A=小王, 100=Marry, 101=Jack, false=25} //3.int size():获取集合元素个数 System.out.println(hashMap.size());//4 //4.Object get(Object key):获取指定key的值,若没有,返回null System.out.println(hashMap.get(101));//Jack //5.boolean containsKey(Object key):是否存在指定的key System.out.println(hashMap.containsKey('A'));//true //6.boolean containsValue(Object value):是否存在指定的value System.out.println(hashMap.containsValue("小王"));//true //7.Object remove(Object key):删除并返回指定键对象Key的键值映射元素 System.out.println(hashMap.remove(100));//Marry //8.void clear():清空整个map集合中的键值对元素,不等于null //hashMap.clear(); //System.out.println(hashMap);//{} //9.boolean isEmpty():判断集合是否为空 System.out.println(hashMap.isEmpty());//false //10.boolean equals(Object obj):判断两个集合是否相同 //11.boolean replace(Object key,Object value):将指定key所映射的值改为value,返回被修改之前的value System.out.println(hashMap.replace('A',"Jerry"));//小王 //12.Set keySet():以Set集合的形式返回Map集合中所有的键对象Key Set set = hashMap.keySet(); Iterator iterator = set.iterator(); while (iterator.hasNext()){ System.out.print(iterator.next()+"t");//A 101 false } System.out.println(); //12.Collection values():以Collection集合的形式返回所有的值对象value Collection values = hashMap.values(); Iterator iterator1 = values.iterator(); while (iterator1.hasNext()){ System.out.print(iterator1.next()+"t");//小王 Jack 25 } System.out.println(); //13.Set> entrySet():将Map集合转换为存储元素类型的Map的Set集合 Set set1 = hashMap.entrySet(); Iterator iterator2 = set1.iterator(); while (iterator2.hasNext()){ Object next = iterator2.next(); Map.Entry next1 = (Map.Entry) next; System.out.println(next1.getKey()+"--->"+next1.getValue());//A--->小王 101--->Jack false--->25 } }
3.linkedHashMap集合:可以确保在遍历map元素时,可以按照添加的顺序实现遍历。
原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。对于频繁的遍历 *** 作,此类执行效率高于HashMap 。
@Test public void test02(){ Map linkedHashMap = new linkedHashMap(); linkedHashMap.put(1001,"小王"); linkedHashMap.put("1002","小吕"); linkedHashMap.put(1003,"小王"); linkedHashMap.put(1004,"小样"); linkedHashMap.put("1005","Tom"); System.out.println(linkedHashMap);//{1001=小王, 1002=小吕, 1003=小王, 1004=小样, 1005=Tom} }二.Hashtable集合
线程安全,效率低,不允许存储的键和值为null。
Properties集合:常用来处理配置文件。key和value都是String类型
@Test public void test01() { Properties properties = new Properties(); FileInputStream fileInputStream = null; try { fileInputStream = new FileInputStream("E:\java\javaSenior\jdbc.properties"); } catch (FileNotFoundException e) { e.printStackTrace(); } try { properties.load(fileInputStream); } catch (IOException e) { e.printStackTrace(); } String name = properties.getProperty("name"); String password = properties.getProperty("password");//若写错了,会输出null System.out.println("name="+name+", password="+password); try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } }三.TreeMap集合
底层采用红黑树(排序二叉树),按照添加的key-value排序,实现排序遍历,此时考虑key的自然排序或定制排序。
public class TreeMapTest { public class TreeMapTest { //自然排序 @Test public void test01(){ Map treeMap = new TreeMap(); Employee e1 = new Employee("Ali", 18); Employee e2 = new Employee("Tom", 16); Employee e3 = new Employee("Jack", 19); Employee e4 = new Employee("Ali", 20); treeMap.put(e1,21); treeMap.put(e2,25); treeMap.put(e3,17); treeMap.put(e4,16); Set set1 = treeMap.entrySet(); Iterator iterator2 = set1.iterator(); while (iterator2.hasNext()){//按照age从小到大输出,age相同按name从小到大 Object next = iterator2.next(); Map.Entry next1 = (Map.Entry) next; System.out.println(next1.getKey()+"--->"+next1.getValue()); } } //定制排序 @Test public void test02(){ Map treeMap = new TreeMap(new Comparator() { @Override public int compare(Object o1, Object o2) { if (o1 instanceof Employee && o2 instanceof Employee) { Employee e1 = (Employee) o1; Employee e2 = (Employee) o2; return Integer.compare(e1.getAge(), e2.getAge()); } throw new RuntimeException("传入的数据类型不一致。"); } }); Employee e1 = new Employee("Ali", 18); Employee e2 = new Employee("Tom", 16); Employee e3 = new Employee("Jack", 19); Employee e4 = new Employee("Ali", 20); treeMap.put(e1,21); treeMap.put(e2,25); treeMap.put(e3,17); treeMap.put(e4,16); Set set1 = treeMap.entrySet(); Iterator iterator2 = set1.iterator(); while (iterator2.hasNext()){//按照age从小到大输出,age相同按name从小到大 Object next = iterator2.next(); Map.Entry next1 = (Map.Entry) next; System.out.println(next1.getKey()+"--->"+next1.getValue()); } } } class Employee implements Comparable{ private String name; private int age; public Employee() { } public Employee(String name, int age ) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge(){ return age; } public void setAge(int age){ this.age = age; } @Override public String toString() { return "Employee{" + "name='" + name + ''' + ", age=" + age + '}'; } //先按照age排序,age相同按照name排序 @Override public int compareTo(Object o) { if(o instanceof Employee){ Employee e = (Employee) o; if(this.getAge()>e.getAge()){ return 1; }else if(this.getAge()定制排序输出:
四.Collections工具类
Collections是 *** 作Collection和Map的工具类。
@Test //Collections的查找、替换 *** 作 public void test02(){ //1.static boolean addAll(Collection, T element):将指定元素添加到指定集合中 ArrayList list = new ArrayList(); Collections.addAll(list,1,22,0,5,8); System.out.println("原集合是:"+list); //2.static Object max(Collection c):按照自然排序,最大的元素 System.out.println("集合中最大的元素是:"+Collections.max(list)); //2.static Object min(Collection c):按照自然排序,最小的元素 System.out.println("集合中最小的元素是:"+Collections.min(list)); //3.static int binarySearch(List list,Object key):使用二分法查找集合中的指定元素,查找之前必须是有序的集合 Collections.sort(list); System.out.println("sort排序后的结果是:"+list); int key = 8; int i = Collections.binarySearch(list, key); System.out.println("元素"+key+"的位置是:"+i); }@Test //Collections的添加、排序 *** 作 public void test101(){ //Collections工具类测试 ArrayList arrayList = new ArrayList(); arrayList.add(123); arrayList.add(23); arrayList.add(10); arrayList.add(0); arrayList.add(-5); System.out.println("原集合是:"+arrayList); //1.static void sort(List list):对集合进行自然排序 Collections.sort(arrayList); System.out.println("sort自然排序后:"+arrayList); //2.static void shuffle(List list):对集合进行随机排序 Collections.shuffle(arrayList); System.out.println("shuffle随机排序后:"+arrayList); //3.static void reverse(List list):对集合进行反转 *** 作(Set集合不存在此方法) Collections.reverse(arrayList); System.out.println("reverse反转后:"+arrayList); //4.static void swap(List list,int i,int j):将指定集合中索引i和j处的元素进行交换 Collections.swap(arrayList,2,4); System.out.println("swap交换后:"+arrayList); //5.void copy(List dest,List src):将集合src中的元素复制到dest中 List list = Arrays.asList(new Object[arrayList.size()]); System.out.println(list.size()); Collections.copy(list,arrayList); System.out.println(list); }扩展面试题1.HashMap的底层实现原理。
以jdk 7为例,执行HashMap map = new HashMap();以后,底层创建了长度是16的一维数组Entry[] table。执行map.put(key,value)添加元素,当执行map.put( key1, value1 )时。首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置。如果此位置上的数据为空,此时的key1-value1添加成功。----情况1
如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表形式存在)),比较key1和已经存在的一个或多个数据的哈希值:如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功。----情况2
如果key1的哈希值和已经存在的某一个数据(key2-vaLue2)的哈希值相同,继续比较:调用key1所在类的equals(key2)
如果equals()返回false:此时key1-value1添加成功。—-情况3
如果equals()返回true:使用value1替换value2.
2.HashMap和Hashtable有何异同?
HashMap线程不安全,增删改查效率高,允许键和值都为null;Hashtable线程安全,效率低
3.Collection和Collections有何异同?
Colection是单列集合的接口,Collections是 *** 作Collection和Map的工具类欢迎分享,转载请注明来源:内存溢出
评论列表(0条)