1、HashMap
HashMap集合本身基于哈希表,它可以保证键的唯一性(Map都是针对键有效),基本格式:HashMap<Key,Value>,其中Key和Value可以是String,Integer等任意类型,包括自定义类型。
下来我们通过实际的例子分别看一下基本类型和自定义类型的情况。
基本类型:
public class HashMapDemo2 {
public static void main(String[] args) {
//创建集合对象
HashMap<Integer, String> map = new HashMap<Integer,String>() ;
//添加元素
map.put(27, "高圆圆") ;
map.put(29, "西施") ;
map.put(28, "唐嫣") ;
map.put(27, "文章") ;
//遍历
Set<Integer> set = map.keySet();
for(Integer key :set) {
String value = map.get(key) ;
System.out.println(key+"---"+value);
}
}
}
自定义类型:
HashMap<Student,String> 键:是一种自定义类型
Student:学生:年龄和姓名String:朝代
如果对象的成员变量值一样,认为同一个人.由于Student是我们自定义的类,所以必须在Student类中重写hashCode()方法和equals()方法,这样才能在成员变量值一样时,认为是同一个人。
HashMap底层哈希表
哈希表:依赖于两个方法 hashCode() ,equals()方法
Student类:
public class Student {
private String name ;
private int age ;
public Student() {
super();
}
public Student(String name, int age) {
super();
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;
}
// 重写hashCode()和equals()方法
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Student))
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
测试类:
public class HashMapDemo4 {
public static void main(String[] args) {
//创建集合对象
HashMap<Student, String> map = new HashMap<Student,String>() ;
//创建学生对象
Student s1 = new Student("西施", 27) ;
Student s2 = new Student("杨贵妃", 35) ;
Student s3 = new Student("王昭君", 30) ;
Student s4 = new Student("貂蝉",28) ;
Student s5 = new Student("西施", 27) ;
//添加元素
map.put(s1, "元朝") ;
map.put(s2, "宋朝") ;
map.put(s3, "唐朝") ;
map.put(s4, "清朝") ;
map.put(s5, "金") ;
//遍历
Set<Student> set = map.keySet() ;
for(Student s :set) {
String value = map.get(s) ;
System.out.println(s.getName()+"---"+s.getAge()+"---"+value);
}
}
}
2、LinkedHashMap
LinkedHashMap<K,V> :是Map接口基于哈希表和链接列表实现的哈希表保证键的唯一性
链接列表保证元素有序性(存储和取出一致)
public class LinkedHashMapDemo {
public static void main(String[] args) {
LinkedHashMap<String, String> map = new LinkedHashMap<String,String>() ;
//添加元素
map.put("it001", "hello");
map.put("it002", "mysql");
map.put("it003", "world");
map.put("it004", "javaweb");
map.put("it001", "javaee");
Set<String> set = map.keySet() ;
for(String key :set) {
String value = map.get(key) ;
System.out.println(key+"----"+value);
}
}
}
3、TreeMap
TreeMap基于红黑树结构的Map接口的实现,所以TreeMap可以对集合进行排序。
1)TreeMap存储基本类型:
public class TreeMapDemo {
public static void main(String[] args) {
TreeMap<String,String> tm = new TreeMap<String,String>();
tm.put("java", "爪哇");
tm.put("hello", "哈喽");
tm.put("abc", "字母");
tm.put("cat", "猫");
tm.put("club", "俱乐部");
tm.put("java", "爪哇2");
Set<String> str = tm.keySet();
for(String key:str) {
String value = tm.get(key);
System.out.println(key+"---"+value);
}
}
}
运行结果:
abc---字母
cat---猫
club---俱乐部
hello---哈喽
java---爪哇2
可以看出,TreeMap集合已经对字符串进行了排序。
2)TreeMap存储自定义类型,TreeMap<Student,String>,对集合进行排序,主要条件:年龄从小到大
public class TreeMapDemo2 {
public static void main(String[] args) {
//创建一个TreeMap集合,使用比较器排序的方式
//匿名内部类的方式
TreeMap<Student, String> tm = new TreeMap<Student,String>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
//主要条件:年龄从小到大
int num =s1.getAge() -s2.getAge() ;
//年龄相同,不一定姓名一样
int num2 = num ==0 ? s1.getName().compareTo(s2.getName()): num ;
return num2 ;
}
} );
//创建学生对象
Student s1 = new Student("唐伯虎", 28) ;
Student s2 = new Student("杜甫", 35) ;
Student s3 = new Student("李白", 40) ;
Student s4 = new Student("李清照", 32) ;
Student s5 = new Student("唐伯虎", 28) ;
Student s6 = new Student("苏轼", 35) ;
//添加到集合中
tm.put(s1, "宋代") ;
tm.put(s2, "唐代") ;
tm.put(s3, "唐代") ;
tm.put(s4, "宋代") ;
tm.put(s5, "清代") ;
tm.put(s6, "清代") ;
//遍历
Set<Student> set = tm.keySet() ;
for(Student key :set) {
String value = tm.get(key) ;
System.out.println(key.getName()+"---"+key.getAge()+"---"+value);
}
}
}
面试题:HashMap集合和Hashtable的区别?
共同点:都是map接口的实现类,都是基于哈希表的实现类
HashMap集合线程不安全的类,不同步,执行效率高(允许键和值是null的)
Hashtable集合线程安全的类,同步,执行效率低(不允许有null键和null值)
我们目前学习过的线程安全的类:
StringBuffer :字符串缓冲区
Vector :List集合
Hashtable :Map集合的
public class HashtableDemo {
public static void main(String[] args) {
//创建HashMap集合对象
HashMap<String, String> hm = new HashMap<String,String>() ;
Hashtable<String, String> ht = new Hashtable<String,String>() ;
//添加元素
hm.put("hello", null);
hm.put(null, "world") ;
//ht.put("hello", null);//NullPointerException
//ht.put(null, "world");//NullPointerException
System.out.println(hm);
//System.out.println(ht);//输出的集合元素的字符串表现形式
}
}
练习:
现有如下需求:
字符串:比如: aaaaabbbbcccddddee ,最终控制台要出现的结果:a(5)b(4)c(3)d(3)e(2)思路:
1)改进:键盘录入一个字符串
2)创建一个HashMap集合key:Character,Value:Integer
3)将录入的字符串转换成字符数组
4)遍历可以获取每一个字符
5)将元素添加到对应的HashMap集合中
使用的put(key,value): 通过判断值是否null ,如果是null表示第一次存储
集合对象.put(ch,1) ;
否则,不是null
Integer那个值++;
集合对象.put(ch,变量Integer值) ;
6)遍历HashMap集合即可
public class Test {
public static void main(String[] args) {
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
//接收数据
System.out.println("请输入一个字符串:");
String line = sc.nextLine() ;
//创建一个HashMap集合来存储对应的字符和值
HashMap<Character, Integer> hm = new HashMap<Character,Integer>() ;
//将字符串转换成字符串
char[] chs = line.toCharArray() ;
//遍历字符数组,获取到每一个字符
for(char ch:chs) {
//获取到每一个字符
Integer i = hm.get(ch) ; //肯定要把值获取到
System.out.println(i);
//通过put方法添加元素,看这个值是否为null
if(i==null) {
//第一次存储
hm.put(ch, 1);
}else {
//不是null,存储了多次
i ++ ;
hm.put(ch, i) ;
}
}
//创建一个字符串缓冲区对象
StringBuilder sb = new StringBuilder() ;
//遍历HashMap集合
Set<Character> set = hm.keySet() ;
for(Character key :set) {
//获取值
Integer value = hm.get(key) ;
sb.append(key).append("(").append(value).append(")") ;
}
String str = sb.toString() ;
System.out.println("str:"+str);
}
}
集合的嵌套:
1、HashMap集合嵌套HashMap集合:
jc(基础班)
高圆圆 27
张三 28
jy(就业班)
赵又廷 29
李四 30
HashMap<String,HashMap<String,Integer>>
代码如下:
public class QianTao {
public static void main(String[] args) {
//创建一个大集合
HashMap<String,HashMap<String,Integer>> map =
new HashMap<String,HashMap<String,Integer>>();
//创建第一子HashMap集合,存储元素
HashMap<String, Integer> hm1 = new HashMap<String,Integer>() ;
hm1.put("高圆圆", 27) ;
hm1.put("张三", 28) ;
//将第一个子集合添加到大集合中
map.put("jc", hm1) ;
//创建第二个子HashMap集合,存储元素
HashMap<String, Integer> hm2 = new HashMap<String,Integer>() ;
hm2.put("赵又廷", 29) ;
hm2.put("李四",30) ;
//添加到大集合中
map.put("jy", hm2) ;
//遍历
Set<String> mapSet = map.keySet() ;
for(String bigKey :mapSet) {
System.out.println(bigKey);
//通过大集合的对象,通过键获取值(HashMap集合)
HashMap<String, Integer> bigValue = map.get(bigKey) ;
//获取所有的键的集合
Set<String> smallMap = bigValue.keySet() ;
for(String smallKey :smallMap) {
Integer smallValue = bigValue.get(smallKey) ;
System.out.println("\t"+smallKey+"---"+smallValue);
}
}
}
}
2、HashMap集合嵌套ArrayList集合
需求:
三国演义吕布
周瑜
笑傲江湖
令狐冲
林平之
神雕侠侣
郭靖
杨过
HashMap<String,ArrayList<String>>
public class HashMapIncludeArrayListTest {
public static void main(String[] args) {
//创建一个大集合对象
HashMap<String, ArrayList<String>> hm = new HashMap<String,ArrayList<String>>() ;
//创建第一个子集合对象
ArrayList<String> array1 = new ArrayList<String>() ;
array1.add("吕布") ;
array1.add("周瑜") ;
//添加到集合中
hm.put("三国演义", array1) ;
//创建第二个子集合对象
ArrayList<String> array2 = new ArrayList<String>() ;
array2.add("令狐冲") ;
array2.add("林平之") ;
//添加到集合中
hm.put("笑傲江湖", array2) ;
//创建第二个子集合对象
ArrayList<String> array3 = new ArrayList<String>() ;
array3.add("郭靖") ;
array3.add("杨过") ;
//添加到集合中
hm.put("神雕侠侣", array3) ;
//遍历
Set<String> set = hm.keySet() ;
for(String key :set) {
System.out.println(key) ;
//通过key获取value
ArrayList<String> value = hm.get(key) ;
for(String s: value) {
System.out.println("\t"+s);
}
}
}
}