双列集合的特点:
1:双列集合一次需存放一对数据,分别为键和值;
2:键不可以重复,值可以重复;
3:键和值是一一对应的,每个键只能找到自己对应的值
4:键加值这个整体我们称之为“键值对” 或者“键值对对象”,在Java中叫做“Entry对象”
Map常用API:
package Map;
import java.util.HashMap;
import java.util.Map;
public class MapTest {
public static void main(String[] args) {
Map<String ,String> map=new HashMap<>();
map.put("12","21");
map.put("13","31");
map.put("14","41");
//put方法:若使用put方法时,主键存在,则会返回被替代的值,如41
// 主键不存在,则返回null
String put = map.put("14", "14");
System.out.println(put);
String put1 = map.put("144", "411");
System.out.println(put1);
//remove: 使用后返回被删键对应的值
String remove = map.remove("144");
System.out.println(remove);
//clear :清空所有键值对元素
//map.clear();
//containsKey:查询map是否存在给出的键
boolean b = map.containsKey("12");
System.out.println(b);
//containsValue: 查询map中是否存在给出的值
boolean b1 = map.containsValue("21");
System.out.println(b1);
//isEmpty: 查询map是否为空
map.isEmpty();
//size: 查询集合的长度
int size = map.size();
System.out.println(size);
}
}
Map的遍历
第一种:通过键找值
package Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapTest1 {
public static void main(String[] args) {
Map<String ,String> map=new HashMap<>();
map.put("12","21");
map.put("13","31");
map.put("14","41");
//Map集合的遍历方式
//1:通过键找值
//获取所有的键将他们放到一个Set集合里
Set<String> strings = map.keySet();
//迭代器遍历
Iterator<String> iterator = strings.iterator();
while(iterator.hasNext()){
String key = iterator.next();
String value = map.get(key);
System.out.println(key+"="+value);
}
//增强for遍历
for (String key : strings) {
String value = map.get(key);
System.out.println(key+"="+value);
}
//lambda表达式
strings.forEach((String key) ->{
String value = map.get(key);
System.out.println(key+"="+value);
}
);
}
}
第二种:增强for
package Map;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapTest2 {
public static void main(String[] args) {
Map<String ,String> map=new HashMap<>();
map.put("12","21");
map.put("13","31");
map.put("14","41");
//这里的map.可以删去,但是要导包
//通过一个方法获得键值对对象,在返回一个set集合
Set<Map.Entry<String, String>> entries = map.entrySet();
//对set集合继行循环
for (Map.Entry<String, String> entry : entries) {
//通过entry调用get方法
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
}
第三种:lambda方法
package Map;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
public class MapTest3 {
public static void main(String[] args) {
Map<String ,String> map=new HashMap<>();
map.put("12","21");
map.put("13","31");
map.put("14","41");
//第三种遍历方式:lambda方法
//基于第二种遍历方式增强for循环
map.forEach(new BiConsumer<String, String>() {
@Override
public void accept(String key, String value) {
System.out.println(key+"="+value);
}
});
//简化lambda表达式
map.forEach(( key, value) ->System.out.println(key+"="+value));
}
}
HashMap
1:HashMap底层是由哈希表结构的
2:依赖hashcode与equal来保证键的唯一
3:如果值为自定义对象,那么无需重写hashcode与equal方法
LinkHashMap
1:由键决定的特点:存取有序,不重复,无索引
2:存取有序因为:底层加上了双链表
TreeMap
1:底层由红黑树实现的
2: 依赖自然排序或者比较器排序,对键进行排序
如果键存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则。
练习
test1
创建一个TreeMap集合,键是学生对象(Student),值是籍贯(String),学生属性姓名和年龄,按照年龄进行排序并遍历要求按照学生的年龄进行排序,如果年龄相同则按照姓名进行排序。
这是是使用了comparable接口方法
如果同时用comparable接口与比较器排序,则优先使用比较器排序
如果键值为integer与String类型的,默认为升序排序
// 学生类
package Map;
import java.util.Objects;
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
@Override
public int compareTo(Student o) {
//this:表示当前要添加的元素
//o:表示红黑树里已有的元素
int i = this.getAge() - o.getAge();
return i=i==0?this.getName().compareTo(o.getName()):i;
}
}
//测试类
package Map;
import java.util.TreeMap;
public class TreeMapTest1 {
public static void main(String[] args) {
TreeMap<Student,String> tm=new TreeMap<>();
Student s1=new Student("zhangsan",20);
Student s2=new Student("lisi",21);
Student s3=new Student("wangwu",22);
Student s4=new Student("zhangsang",20);
tm.put(s1,"anhuiu");
tm.put(s2,"shangdong");
tm.put(s3,"heinan");
tm.put(s4,"anhui");
System.out.println(tm);
}
}
test2
统计字符串"aababcabcdabcde"中各个字符出现次数,且降序排序
运行结果为
a(5)b(4)c(3)d(2)e(1)
package Map;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
public class TreeMapTest2 {
public static void main(String[] args) {
String s = "aababcabcdabcde";
TreeMap<Character, Integer> tm = new TreeMap<>(new Comparator<Character>() {
@Override
public int compare(Character o1, Character o2) {
return o1.compareTo(o2);
}
}); // Changed to Character for counting chars
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i); // Get each character from the string
if (tm.containsKey(c)) {
int count = tm.get(c);
count++;
tm.put(c, count);
} else {
tm.put(c, 1);
}
}
//定义一个StringBuilder 对象,用来拼接字符串
StringBuilder sb=new StringBuilder();
for (Map.Entry<Character, Integer> entry :tm.entrySet() ) {
sb.append(entry.getKey()).append("(").append(entry.getValue()).append(")");
}
System.out.println(sb);
}
}
总结
HashMap,LinkedHashMap,TreeMap
使用时HashMap效率最好,如果要存取有序,则使用LinkedHashMap,如果要排序则使用TreeMap。