增改
value put(k,v);
返回key前一个对应的值
删
void clear
value remove(key)
查
boolean containsKey(k)
boolean containsValue(v)
boolean isEmpty()
value get(key) 如果没有该key,则返回null,可以判断是否包含指定key
int size()
Map<Integer,String> map = new HashMap<Integer, String>();
//增加修改
System.out.println(map.put(1, "wangcai")); //null
System.out.println(map.put(1, "xiaoqiang")); //wangcai 集合中的键不能重复,重复就覆盖
System.out.println(map); //{1=xiaoqiang}
map.put(2, "zhgangshan");
map.put(3, "lisi");
//删除
System.out.println("remove:.."+map.remove(2)); //remove:..zhgangshan
System.out.println(map); //{1=xiaoqiang, 3=lisi}
//判断
System.out.println("containsKey:.."+map.containsKey(2)); //containsKey:..false
System.out.println("containsvalue:.."+map.containsValue("zhgangshan"));
//获取
System.out.println(map.get(3)); //lisi
Set<Integer> keys = map.keySet();
Iterator<Integer> it = keys.iterator();
while(it.hasNext()) {
Integer key = it.next();
String value = map.get(key);
System.out.println(key+":"+value);
}
Set<Map.Entry<Integer,String>> entry = map.entrySet();
Iterator<Map.Entry<Integer,String>> it = entry.iterator();
while(it.hasNext()) {
Map.Entry<Integer,String> me = it.next();
Integer key = me.getKey();
String value = me.getValue();
System.out.println(key+":"+value);
}
Collection<String> values = map.values();
Iterator<String> it = values.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
底层还是哈希表,所以判断键的重复,hashcode equals
HashMap<Student,String> hs = new HashMap<Student,String>();
hs.put(new Student("s1",21), "上海");
hs.put(new Student("s2",22), "北京");
hs.put(new Student("s3",23), "成都");
hs.put(new Student("s4",24), "广州");
hs.put(new Student("s1",21), "杭州"); //自动调用Person的equals,hashCode方法,覆盖
Iterator<Student> it = hs.keySet().iterator();
while(it.hasNext()) {
Student key = it.next();
String value = hs.get(key);
System.out.println(key.getName()+":"+key.getAge()+"---"+value);
}
key 唯一 升序 红黑树 如果使用TreeMap存储自定义类,必须具备比较器,否则报错
自定义类实现Comparable
TreeMap<Person,String> hs = new TreeMap<Person,String>();
hs.put(new Person("s1",21), "上海");
hs.put(new Person("s2",26), "北京");
hs.put(new Person("s3",23), "成都");
hs.put(new Person("s4",24), "广州");
hs.put(new Person("s1",21), "杭州");
//自动调用Person的equals,hashCode方法
Iterator<Map.Entry<Person,String>> it = hs.entrySet().iterator();
while(it.hasNext())
{
Map.Entry<Person,String> me = it.next();
Person key =me.getKey();
String value = me.getValue();
System.out.println(key.getName()+":"+key.getAge()+"---"+value);
}
/*
s1:21---杭州
s3:23---成都
s4:24---广州
s2:26---北京
*/
public class Person extends Object implements Comparable<Person> {
private String name;
private int age;
public Person(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;
}
@Override
public int compareTo(Person p) {
int temp = this.age-p.age;
return temp;
}
}
使用外部比较器
TreeMap<Student,String> hs = new TreeMap<Student,String>(new ComparatorByName());
hs.put(new Student("s1",21), "上海");
hs.put(new Student("s2",26), "北京");
hs.put(new Student("s3",23), "成都");
hs.put(new Student("s4",24), "广州");
hs.put(new Student("s1",21), "杭州"); //自动调用Person的equals,hashCode方法
Iterator<Map.Entry<Student,String>> it = hs.entrySet().iterator();
while(it.hasNext()) {
Map.Entry<Student,String> me = it.next();
Student key = me.getKey();
String value = me.getValue();
System.out.println(key.getName()+":"+key.getAge()+"---"+value);
}
public class ComparatorByName implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
// Person p1 = (Person)o1;
// Person p2 = (Person)o2;
int temp = p1.getName().compareTo(p2.getName());
return temp==0?p1.getAge()-p2.getAge() : temp;
}
}
TreeMap源码分析
public class TestTreeMap {
/***
* TreeMap的底层实现
*
* private final Comparator<? super K> comparator; 外部比较器,用于比较大小的
* private transient Entry<K,V> root; //代表的是树根
* public TreeMap() {
comparator = null;
}
public V put(K key, V value) {
Entry<K,V> t = root; //指向树根
if (t == null) {
//比较大小
compare(key, key); // type (and possibly null) check
//创建一个根节点
root = new Entry<>(key, value, null);
size = 1; //个数++
modCount++;
return null;
}
int cmp;
Entry<K,V> parent; //父节点
// split comparator and comparable paths
*
Comparator<? super K> cpr = comparator; //null
//如果外部比较器不等于null,说明外部比较器存在
if (cpr != null) {
do {
parent = t; //把root赋给父节点
cmp = cpr.compare(key, t.key); //调用外部比较器的比较方法开始比大小,结果是一个int类型的值
if (cmp < 0)
t = t.left; //在左子树上查找
else if (cmp > 0) //在右子树上查找
t = t.right;
else
return t.setValue(value); //找到了,值进行覆盖
} while (t != null);
}
else { //外部比较器不存在,使用内部比较器进行比较
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t; //root赋给父节点
cmp = k.compareTo(t.key); //调用内部比较器的比较大小的方法,比较结果为int类型
if (cmp < 0)
t = t.left; //在左子树上查找
else if (cmp > 0) //在右子树上查找
t = t.right;
else
return t.setValue(value); 找到了值的覆盖
} while (t != null);
}
//创建一个节点
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e; //添加到左子树
else
parent.right = e; //添加到右子树
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
*/
public static void main(String[] args) {
//创建集合对象
//TreeMap treeMap=new TreeMap();
//创建外部比较器对象,定义比较规则
Comparator comLength=new CompareLength();
TreeMap treeMap=new TreeMap(comLength);
//添加数据
treeMap.put("hello", 123);
treeMap.put("world1", 456);
treeMap.put("hello11", 789);
treeMap.put("java", 1000);
System.out.println("集合中元素的个数:"+treeMap.size());
System.out.println(treeMap);
System.out.println(treeMap.containsKey("hello")+"\t"+treeMap.containsKey("sql"));
System.out.println(treeMap.containsValue(789)+"\t"+treeMap.containsValue(1002));
System.out.println(treeMap.get("java"));
}
}
HashMap<Integer,String> hs = new LinkedHashMap<Integer,String>(); //保证存入和取出顺序一致
hs.put(7, "zhangsan1");
hs.put(8, "zhangsan2");
hs.put(2, "zhangsan3");
Iterator<Map.Entry<Integer,String>> it = hs.entrySet().iterator();
while(it.hasNext()) {
Map.Entry<Integer,String> me = it.next();
Integer key = me.getKey();
String value = me.getValue();
System.out.println(key+":"+value);
}
String str = "f+_dgavcbsacADdfs";
char[] chs = str.toCharArray();
Map<Character,Integer> map = new TreeMap<>();
for(int i=0;i<chs.length;i++) {
if(chs[i]>='a' && chs[i]<='z' || chs[i]>='A' && chs[i]<='Z') {
Integer value = map.get(chs[i]);
if(value==null) {
map.put(chs[i], 1);
}else {
map.put(chs[i], value+1);
}
}
}
StringBuilder sb = new StringBuilder();
Iterator<Character> it = map.keySet().iterator();
while(it.hasNext()) {
Character key = it.next();
Integer value = map.get(key);
sb.append(key+"("+value+")");
}
System.out.println(sb.toString());
在JDK8中HashMap的底层是:数组+链表(散列表)+红黑树
在散列表中有装载因子这么一个属性,当装载因子*初始容量小于散列表元素时,该散列表会再散列,扩容2倍!
装载因子的默认值是0.75,无论是初始大了还是初始小了对我们HashMap的性能都不好
装载因子初始值大了,可以减少散列表再散列(扩容的次数),但同时会导致散列冲突的可能性变大(散列冲突也是耗性能的一个操作,要得操作链表(红黑树)!
装载因子初始值小了,可以减小散列冲突的可能性,但同时扩容的次数可能就会变多!
初始容量的默认值是16,它也一样,无论初始大了还是小了,对我们的HashMap都是有影响的:
初始容量过大,那么遍历时我们的速度就会受影响~
初始容量过小,散列表再散列(扩容的次数)可能就变得多,扩容也是一件非常耗费性能的一件事~
从源码上我们可以发现:HashMap并不是直接拿key的哈希值来用的,它会将key的哈希值的高16位进行异或操作,使得我们将元素放入哈希表的时候增加了一定的随机性。
还要值得注意的是:并不是桶子上有8位元素的时候它就能变成红黑树,它得同时满足我们的散列表容量大于64才行的~