
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条)