集合 MAP
Map 接口
Map本身是接口,存储的是键值对,一个元素是一个KEY和VALUE对,Key必须是唯一的(必点实现了去重),value值是随意的,是可以重复的.
1. HashMap :底层是哈希表,线程不安全的
2. TreeMap:底层是二叉树,线程不安全的
方法:
1. 增加:put(key,value),如果存入重复的Key,会替换之前的value,返回之前的value
2. 删除:remove(Object key) 根据key删除元素,返回值就是被删掉的值,void clear() 删除全部 != null
3. 获取:get(Object key) 根据key查找元素,int size() 获取键值对的个数
4. 常用的判断:boolean isEmpty() //空map!=null;boolean containsKey(K key) 是否包含当前的key;boolean containsValue(V value) 是否包含当前的value
两种遍历方法:
1. 遍历方法一:Set keySet()
1.原理:先得到所有的key,放入一个Set中,利用Set的迭代器进行遍历得到key,在利用key获取value
2.步骤:
第一步:先得到装着key的set: Set set = map.keySet();keySet();将Map中所有的键存入Set集合中,通过集合中迭代器的方式进行遍历。
第二步:遍历set,得到key,再根据key获取value:
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
String key = iterator.next();
System.out.println(“key:”+key+" value:"+map.get(key));
}
2. 遍历方法二:Set<Map.Entry<K,V>> entrySet()
1.原理:先得到所有的entry,放入一个Set中,利用Set的迭代器进行遍历得到entry实体,在利用entry的方法获取key和value
2.步骤:
第一步:先得到装着Entry实体的set:Set<Map.Entry<String,String>> set = map.entrySet();
第二步:遍历set,得到entry实体,再调用entry实体对象的方法获取key和value:Iterator<Map.Entry<String,String>> iterator = set.iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
//通过setValue可以将map的原始值改变,但是一般在使用entrySet的时候,是进行遍历.不进行值的改变.
//entry.setValue(“bingbing”);
System.out.println(“key1:”+entry.getKey()+" value1:"+entry.getValue());
}
3.Set<Map.Entry<K,V>> entrySet() //返回此映射中包含的映射关系的 Set 视图。 Map.Entry表示映射关系。entrySet():迭代后可以e.getKey(),e.getValue()取key和value。返回的是Entry接口 。
遍历说明:
说明:
①Set keySet():返回值是个只存放key值的Set集合(集合中无序存放的),迭代后只能通过get()取key。
②Set<Map.Entry<K,V>> entrySet():返回映射所包含的映射关系的Set集合(一个关系就是一个键-值对),就是把(key-value)作为一个整体一对一对地存放到Set集合当中的。迭代后可以e.getKey(),e.getValue()取key和value。返回的是Entry接口
效率比较:1.通过查看源代码发现,调用这个方法keySetMap.keySet()会生成KeyIterator迭代器,其next方法只返回其key值2.而调entrySetMap.entrySet()方法会生成EntryIterator 迭代器,其next方法返回一个Entry对象的一个实例,其中包含key和value. 3.二者在此时的性能应该是相同的,但方式一再取得key所对应的value时,此时还要访问Map的这个方法,这时,方式一多遍历了一次table
entry,是Map里面的静态接口,为什么怎么做?entry对应的是一个实体,成了内部接口的话,map对象可以直接调用(map.entry.getKey)
MAP通过转成collection实现遍历
Map和Set底层是一样的,只是Set没有管value
HashMap:去重,因为HashMap的底层与HashSet的底层实现一样,只是对HashMap去重的时候,操作的是key
注意一::HashMap可以实现排序:因为他的底层数据结构是由数组+链表+二叉树共同实现的.所以可以排序.同时这样做的目的是提高数据存储的效率.
注意二:面试题:
1. hashMap与HashTable的区别?线程安全,HashTable value不能为空
2. HashMap的底层实现:在JDK1.6,JDK1.7中,HashMap采用位桶+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,HashMap采用位桶+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
TreeMap:去重和排序,底层与TreeSet一致,在进行排序去重的时候就是去操作key.
注意点:
1.什么类型的数据类型可以作为key?
a:实现了Comparable接口的compareTo()方法
b:实现了Comparator接口的compare()方法
可以的代表:String,包装类,自定义的实现了要求的类
不可以的代表:数组,ArrayList,LinkedList(如果给他们建立的比较器也可以比较,但是不建议使用)
2.元素可不可以作为key,跟元素内部的成员没有关系
public class Demo5 {
public static void main(String[] args) {
TreeMap<Dog, String> map = new TreeMap<>();
//如果没有重写compareTo或者compare方法,put内部无法调用元素的这两个方法.所以会报错
map.put(new Dog(), "haha");
}
}
class Dog implements Comparable<Dog>{
//2.元素可不可以作为key,跟元素内部的成员有没有关系
Object object;
@Override
public int compareTo(Dog o) {
// TODO Auto-generated method stub
return 0;
}
}
可变参数:参数的个数可以改变
1. 作用:简化代码,简化操作
public class Demo6 {
public static void main(String[] args) {
sum(2, 3);//值传递
//址传递
int[] arr = {3,4,5};
sum(arr);
//可变参数
//可变参数的特点
//1.给可变参数传值的实参可以直接写,个数不限制,内部会自动的将他们放入可变数组中.
sum1(5,6,7,8,9,3,3,4);
//2.当包括可变参数在内有多个参数时,可变参数必须放在最后面,并且一个方法中最多只能有一个可变参数
//3.当可变参数的方法与固定参数的方法是重载关系时,调用的顺序,固定参数的优先于可变参数的.
sum3(2,3);
}
//求两个数的和
//值传递
public static int sum(int a,int b) {
return a+b;
}
//址传递
public static int sum(int[] a) {
int sum = 0;
for (int i = 0; i < a.length; i++) {
sum+=a[i];
}
return sum;
}
//通过可变参数
//构成:数据类型+... 实际上就是数据类型[] 即:int[]
public static int sum1(int... a) {
int sum = 0;
for (int i = 0; i < a.length; i++) {
sum+=a[i];
}
return sum;
}
//2.当包括可变参数在内有多个参数时,可变参数必须放在最后面,并且一个方法中最多只能有一个可变参数
public static int sum2(float b,int... a) {
int sum = 0;
for (int i = 0; i < a.length; i++) {
sum+=a[i];
}
return sum;
}
//3.当可变参数的方法与固定参数的方法是重载关系时,调用的顺序,固定参数的优先于可变参数的.
public static int sum3(int a, int b) {
System.out.println("a");
int sum = 0;
return sum;
}
public static int sum3(int... a) {
System.out.println("b");
int sum = 0;
return sum;
}
}
增强for循环:可以遍历的内容有:数组,Collection,Map.但是Map不能直接遍历
- 原理:每次遍历开始后,会自动从数组中依次取出一个元素放入前面的变量中,当次循环的操作使用的就是这个元素.遍历完成之后,会自动进行第二次遍历.一直到数组的末尾.所有元素遍历结束.循环停止.
- 遍历Map
for (String key : map.keySet()) {
}
for (Map.Entry<String, String> entry: map.entrySet()) {
}
Collections:封装了大量操作的Collection的工具
1. 使用Collection排序:
package test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Collections1{
public static void main(String[] args) {
//要求:存储多个数据,可排序,可重复
ArrayList<String> list = new ArrayList<>();
list.add("java");
list.add("java1haha");
list.add("java2BigData");
list.add("java3ok");
list.add("java2");
System.out.println(list);
//使用Collections排序
//第一种排序:默认按照字典进行排序
//注意:要想list中的元素可以按照字典排序,元素必须实现Comparable接口
Collections.sort(list);//加入的是String 但是String 已经实现了Comparable
System.out.println("默认的字典排序:"+list);
//按照从短到长排序
//使用比较器
ComStrWithLength1 comStrWithLength = new ComStrWithLength1();
Collections.sort(list, comStrWithLength);
System.out.println("从短到长排序:"+list);
//按照从长到短排序
Comparator<String> comparator1 = Collections.reverseOrder(comStrWithLength);
Collections.sort(list, comparator1);
System.out.println("从长到短排序:"+list);
//倒叙字典排序
Comparator<String> comparator2 = Collections.reverseOrder();
Collections.sort(list, comparator2);
System.out.println("倒叙字典排序:"+list);
Collections.reverse(list);
System.out.println("现有顺序的反转排序:"+list);
//求最大值
String max = Collections.max(list, comStrWithLength);
System.out.println(max);
}
}
class ComStrWithLength1 implements Comparator<String>{
@Override
public int compare(String o1, String o2) {
int num = o1.length()-o2.length();
return num==0?o1.compareTo(o2):num;
}
}
哈希表
hashMap的存值原理?