一、Map接口
二、HashMap实现类、LinkedHashMap实现类
1.HashMap的特点
1)无序,唯一(key唯一,因为底层key按照哈希表(数组+链表)的结构)
2)放入集合的数据的类中,必须重写hashCode()和equals()
2.HashMap常用方法
1)增:put(Key key,V value)
2)删:clear()
remove(Object key)
3)改:
4)查:size()
keySet():返回key
values():返回value
get(Object key):根据key得到value
entrySet():返回key和value
5)判断:containsKey(Object key):是否存在key
containsValue(Object value):是否存在value
equals(Object o):两个集合元素是否相等
isEmpty()
package com.rzd.no03map;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Demo01 {
public static void main(String[] args) {
//创建一个Map集合来表示学生的学号、姓名键值对,使用Map接口下的HashMap实现类来创建
Map<Integer, String> hm = new HashMap<>();
//常用方法
System.out.println("增:");
//1.增:put(Key key,V value)
hm.put(1001, "lili");
//System.out.println(hm1.put(1001, "lili")); 如果对上面一句的返回结果进行输入,得到的结果是null
hm.put(1001, "alili");
//System.out.println(hm1.put(1001, "lili")); 添加key相同而value不相同的数据,返回结果是value值alili,说明添加的是这条数据
hm.put(1005,"nana");
hm.put(1028,"feifei");
hm.put(1012,"feifei");
hm.put(1018,"taotao");
System.out.println(hm.size()); //5
System.out.println(hm); //Map集合,无序,唯一(key唯一),{1028=feifei, 1012=feifei, 1001=alili, 1018=taotao, 1005=nana}
System.out.println("删:");
//2.删:remove(Object key)、clear()
hm.remove(1018);
System.out.println(hm); //{1028=feifei, 1012=feifei, 1001=alili, 1005=nana}
/*hm1.clear();
System.out.println(hm1); //{}*/
System.out.println("查:");
//3.查:entrySet()、get(Object key)、keySet()、size()、values()
//对集合中进行遍历查看
//1)keySet():遍历key,返回的是一个Set集合,且这个集合里面的参数类型是key的类型。
//所以创建一个Set类型的对象来接收
Set<Integer> set = hm.keySet();
//对set使用for循环遍历
for (Integer i:set){
System.out.print(i+"\t"); //1028 1012 1001 1005
}
System.out.println();
//2)values():遍历value,返回的是一个Collection集合,集合的参数类型是value的类型。
//所以创建一个Collection类型的对象来接收
Collection<String> values = hm.values();
//对values使用for循环遍历
for (String s:values){
System.out.print(s+"\t"); //feifei feifei alili nana
}
System.out.println();
//3)get(Object key):通过key的值遍历value
//先创建一个对象接收key的值,通过调用hm1.get(key)得到该方法的返回值value
Set<Integer> set1 = hm.keySet();
for (Integer i:set1){
System.out.print(hm.get(i)+"\t"); //feifei feifei alili nana
}
System.out.println();
//4)entrySet():返回值是一个Set集合,Set集合里的每一个元素都是
//Map(接口)集合里面的Entry(接口)的一个具体的对象,这个对象就是key和value的封装
Set<Map.Entry<Integer, String>> entries = hm.entrySet();
//对Set集合进行遍历
for (Map.Entry<Integer, String> e:entries){ //参考上面写的也是引用类型 参数名:对象
System.out.print(e.getKey()+"="+e.getValue()+"\t");
}
System.out.println();
System.out.println("判断:");
//4.判断:
//containsKey(Object key):集合中是否包含key
System.out.println(hm.containsKey(1028)); //true
System.out.println(hm.containsKey(1111)); //false
//containsValue(Object value):集合中是否包含key
System.out.println(hm.containsValue("nana")); //true
//equals(Object o):判断两个集合元素是否相同
Map<Integer, String> hm1 = new HashMap<>();
hm1.put(1111,"aaaa");
hm1.put(2222,"bbbb");
hm1.put(3333,"cccc");
hm1.put(4444,"dddd");
Map<Integer, String> hm2 = new HashMap<>();
hm2.put(1111,"aaaa");
hm2.put(2222,"bbbb");
hm2.put(3333,"cccc");
System.out.println(hm1==hm2); //false,判断集合地址是否相同
System.out.println(hm1.equals(hm2)); //true,判断集合元素是否相同,说明Map中对equals方法进行了重写
//isEmpty():判断是否为空
hm.clear();
System.out.println(hm.isEmpty()); //true
}
}
3.LinkedHashMap实现类
按照输入的顺序输出HashMap,底层是哈希表+链表
特点:唯一,有序(按照输入的顺序输出)
Map<Integer, String> hm = new LinkedHashMap<>();
hm.put(1001, "lili");
hm.put(1001, "alili");
hm.put(1005,"nana");
hm.put(1028,"feifei");
hm.put(1012,"feifei");
hm.put(1018,"taotao");
System.out.println(hm.size()); //5
System.out.println(hm); //{1001=alili, 1005=nana, 1028=feifei, 1012=feifei, 1018=taotao}
4、Hashtable实现类
使用与HashMap相同
区别为:
HashMap:JDK1.2开始,效率高,线程不安全,可以存入key为空的元素,且也遵循key唯一的特点。
Hashtable:JDK1.0开始,效率低,线程安全,不能存入key为空的元素,会报NullPointerException空指针异常
三、HashMap源码分析
1.原理分析
创建一个HashMap集合存放学生年龄-姓名键值对
可以看到,有两条key为1的数据,put命令的返回值为当前的value,对于hm.put(10, "明明")返回的时null,说明存入的不是这条数据,对于hm.put(10, "花花"),返回值却是"明明"。这里就需要分析原理及源码来解释。
public class Demo03 {
public static void main(String[] args) {
HashMap<Integer, String> hm = new HashMap<>();
System.out.println(hm.put(10, "明明")); //null,说明存入的不是这条的key
hm.put(15,"红红");
hm.put(13,"兰兰");
System.out.println(hm.put(10, "花花")); //输出了value值"明明"
hm.put(19,"菲菲");
System.out.println(hm.size());
System.out.println(hm);//{19=菲菲, 10=花花, 13=兰兰, 15=红红} 无序,唯一
}
}
2.源码分析
1)HashMap的泛型<K,V>在创建对象的时候就确定了,这里K=Integer,V=String
HashMao实现了Map接口,但是HashMap继承的AbstractMap类也实现了Map接口,这是一种荣誉冗余写法
2)DEFAULT_INITIAL_CAPACITY:默认的初始化长度,定定义了要赋给数组长度的值16
1<<4,表示1左移4位,0000 0001 左移4位:0001 0000=2的4次方=16
3)MAXIMUM_CAPACITY:1左移30位,每左移1位就是乘以2,这里可以看到是定义了一个非常大的数
4)DEFAULT_LOAD_FACTOR=0.75:负载因子/加载因子,后面会将0.75赋给loadFactor
5)底层主数组为Entry类型
6)size:集合中添加的元素的个数
7) threshold:默认为0,用来表示数组扩容的边界值
8)无参构造器
9)put()
返回值是
四、TreeMap实现类
1.特点
唯一,有序(按照升序或降序)
底层原理:二叉树,key遵照二叉树的特点,且放入集合的类需要实现内部或外部比较器
2.TreeMap的使用
1)key为String类型数据
可以看到遵循key升序的顺序排序
//创建学生姓名-学号键值对
Map<String,Integer> tm = new TreeMap<>();
tm.put("alili",1001);
tm.put("clili",1032);
tm.put("elili",1007);
tm.put("blili",1011);
tm.put("dlili",1001);
System.out.println(tm); //{alili=1001, blili=1011, clili=1032, dlili=1001, elili=1007}
2)key为自定义的类型数据
内部比较器
class Student implements Comparable<Student>{
String name;
int age;
double height;
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;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public Student(String name, int age, double height) {
this.name = name;
this.age = age;
this.height = height;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", height=" + height +
'}';
}
//内部比较器
@Override
public int compareTo(Student o) {
//return 0;
return this.getAge()-o.getAge();
}
}
//key为自定义的类
//内部比较器
Map<Student, Integer> tm1 = new TreeMap<>();
tm1.put(new Student("alili",13,150.8),1001);
tm1.put(new Student("clili",19,180.3),1032);
tm1.put(new Student("elili",28,160.8),1007);
tm1.put(new Student("blili",7,199.2),1011);
tm1.put(new Student("dlili",14,148.6),1001);
System.out.println(tm1);
//{Student{name='blili', age=7, height=199.2}=1011,
// Student{name='alili', age=13, height=150.8}=1001,
// Student{name='dlili', age=14, height=148.6}=1001,
// Student{name='clili', age=19, height=180.3}=1032,
// Student{name='elili', age=28, height=160.8}=1007}
外部比较器
//外部比较器
class Bijiao1 implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
//return 0;
return o1.getAge()-o2.getAge();
}
}
class Bijiao2 implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
//return 0;
return o1.getName().compareTo(o2.getName());
}
}
class Bijiao3 implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
//return 0;
return ((Double)(o1.getHeight())).compareTo((Double)(o2.getHeight()));
}
}
//外部比较器
//需要先创建外部比较器对象
Comparator bj3 = new Bijiao3();
Map<Student, Integer> tm2 = new TreeMap<>(bj3);
tm2.put(new Student("alili",13,150.8),1001);
tm2.put(new Student("clili",19,180.3),1032);
tm2.put(new Student("elili",28,160.8),1007);
tm2.put(new Student("blili",7,199.2),1011);
tm2.put(new Student("dlili",14,148.6),1001);
System.out.println(tm2);
//{Student{name='dlili', age=14, height=148.6}=1001,
// Student{name='alili', age=13, height=150.8}=1001,
// Student{name='elili', age=28, height=160.8}=1007,
// Student{name='clili', age=19, height=180.3}=1032,
// Student{name='blili', age=7, height=199.2}=1011}
匿名内部类
//匿名内部类写法
Map<Student, Integer> tm3 = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//return 0;
return o1.getName().compareTo(o2.getName());
}
});
tm3.put(new Student("alili",13,150.8),1001);
tm3.put(new Student("clili",19,180.3),1032);
tm3.put(new Student("elili",28,160.8),1007);
tm3.put(new Student("blili",7,199.2),1011);
tm3.put(new Student("dlili",14,148.6),1001);
System.out.println(tm3);
//{Student{name='alili', age=13, height=150.8}=1001,
// Student{name='blili', age=7, height=199.2}=1011,
// Student{name='clili', age=19, height=180.3}=1032,
// Student{name='dlili', age=14, height=148.6}=1001,
// Student{name='elili', age=28, height=160.8}=1007}