Map接口
① 映射(map)是一个存储键/值对的对象。给定一个键,可以查询到它的值,键和值都是对象;
② 键必须是唯一的,值可以重复;
③ 有些映射可以接收null键和null值,而有的不行;
④ 下面的接口可以支持映射:
接口 |
描述 |
Map |
映射唯一关键字给值 |
Map.Entry |
描述映射中的元素(关键字/值对)。这是Map的一个内部类 |
SortedMap |
扩展Map以便关键字按升序保持 |
⑤ Map接口映射唯一键到值;
⑥ 键(key)是以后用于检索值的对象。给定一个键和一个值,可以存储这个值到Map对象中,以后可以使用对应键来检索它;
⑦ Map接口定义的方法:
a) int size()
b) boolean isEmpty()
c) boolean containsKey(Object key)
d) boolean containsValue(Object value)
e) V get(Object key)
f) V put(K key,V value)
g) V remove(Object key)
h) Collection<V> values()
i) Set<Map.Entry<K,V>> entrySet() 返回包含映射关系的set视图
⑧ Map.Entry接口代表映射项(键-值对)类型,是Map的嵌套类型;
⑨ Map接口定义的entrySet()方法返回包含映射项Entry的集合(Set),集合中的元素是Map.Entry类型;
⑩ Map.Entry接口定义的方法:
a) K getKey()
b) V getValue()
c) V setValue(V value)
HashMap及常用API
① HashMap类是基于哈希表的map接口的实现,并允许使用null键和null值;
② 构造方法:
a) HashMap()
b) HashMap(Map m)
c) HashMap(int capacity)
d) HashMap(int capacity,float fillRatio)
③ HashMap实现Map并扩展AbstractMap,本身并没有增加任何新的方法;
④ 散列映射不保证它的元素的顺序,元素加入散列映射的顺序并不一定是它们被迭代读出的顺序;
添加及输出
1 Map<String, String> map = new HashMap<String, String>(); 2 map.put("zhangsan", "张三"); 3 map.put("zhangsan", "李四");//会覆盖上面的‘张三‘值 4 map.put("jay", "小明"); 5 map.put("marry", "小红"); 6 System.out.println(map);
输出结果:
{jay=小明, zhangsan=李四, marry=小红}
获取map中的所有键
1 Set<String> keys=map.keySet(); 2 for(String key:keys){ 3 System.out.println(key); 4 }
输出结果:
jay
zhangsan
marry
获取map中的所有值
1 Collection<String> values=map.values(); 2 for(String value:values){ 3 System.out.println(value); 4 }
输出结果:
小明
李四
小红
得到key的同时得到key所对应的值
1 Set<String> keys=map.keySet(); 2 for(String key:keys){ 3 System.out.println(key+"--"+map.get(key)); 4 }
输出结果:
jay--小明
zhangsan--李四
marry--小红
1 System.out.println(map.size());// 返回此映射中的键-值映射关系数 2 System.out.println(map.isEmpty());// 如果此映射不包含键-值映射关系,则返回 true
输出结果:
3
false
返回此映射所包含的映射关系的 Set
视图
1 //当我们调用put(key,value)方法时,首先会把key和value封装到 2 //Entry这个静态内部类对象中,把Entry对象再添加到数组中, 3 //所以我们想获取map中的所有键值对时,我们只要获取数组中的所有Entry对象 4 //接下来调用Entry对象中的getKey和getValue方法就能获得键值对 5 Set<Entry<String, String>> entrys= map.entrySet(); 6 for(Entry<String,String> entry:entrys){ 7 System.out.println(entry.getKey()+"----"+entry.getValue()); 8 }
输出结果:
jay----小明
zhangsan----李四
marry----小红
put方法步骤解析
1 /* 2 * put方法步骤解析 3 * HashMap调用默认构造方法会产生一个底层长度为16的Entry数组 4 * int hash=hash(key.hashCode()); 5 * 首先调用key的hashCode方法来得到一个整数--哈希码 6 * 把哈希码作为参数传到hash函数中进行运算--散列运算--得到一个整型--散列值 7 * int i=indexFor(hash,table.length) 8 * 把散列值和数组的长度来进行运算,最终得到存放到数组的位置(i) 9 * 10 * HashMap内部的结构是数组链表结构 11 * 因为不同的key有可能算出来的事相同的散列值,根据散列值计算出存放 12 * 到数组的下标会冲突 13 * */
int i=hash(zhang.hashCode());
int j=hash(li.hashCode());
i可能与j相同,假如都为4,则 zhan—‘张三’ 存放在4的位置上,
li—‘李四’ 存放在4的位置上
get方法解析
1 /* 2 * get方法解析 3 * 使用关键字查找时,可能会在同一个散列值位置下有多个key-value, 4 * 多个key-value以链表的形式存放,再一个一个比较,直到找到为止 5 * 若找不到返回null 6 * */ 7
哈希码的产生和使用
① 当调用对象的hashCode()方法时就会返回当前对象的哈希码值。支持此方法是为了提高哈希表的性能;
② hashCode的常协议:
a) 在Java应用程序执行期间,在对同一对象多次调用hashCode方法时,必须一致地返回相同的整数,前提是将对象进行equals比较时所用的信息没有被修改,从某一应用程序的一次执行到同一应用程序的另一次执行该整数无需保持一致;
b) 如果根据equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用hashCode方法都必须生成相同的整数结果;
注:这里说的equals(Object)方法是指Object类中未被子类重写过的equals方法;
c) 如果根据equals(java.lang.Object)方法,两个对象不相等,那么对这两个对象中的任一对象上调用hashCode方法不要求一定生成不同的整数结果。但是,我们应该意识到,为不相等的对象生成不同的整数结果可以提高哈希表的性能;
创建一个Student 类
1 class Student{ 2 private String name; 3 private int age; 4 public Student(String name, int age) { 5 super(); 6 this.name = name; 7 this.age = age; 8 } 9 public String getName() { 10 return name; 11 } 12 public void setName(String name) { 13 this.name = name; 14 } 15 public int getAge() { 16 return age; 17 } 18 public void setAge(int age) { 19 this.age = age; 20 } 21 }
在主方法中创建对象,赋值,查看元素
1 Map<Student,String> map=new HashMap<Student, String>(); 2 map.put(new Student("zhang",20), "张三"); 3 map.put(new Student("li",30), "李四"); 4 map.put(new Student("wang",20), "王五"); 5 map.put(new Student("li",30), "小明"); 6 System.out.println(map); 7 System.out.println(map.size());
输出结果:
{[email protected]=小明, [email protected]=张三, [email protected]=李四, [email protected]=王五}
4
此处放入2个new Student("li",30)相同的键,被看作是2个
若要当做1个则要重写hashCode 方法与equals方法,(可生成)。
1 @Override 2 public int hashCode() { 3 final int prime = 31; 4 int result = 1; 5 result = prime * result + age; 6 result = prime * result + ((name == null) ? 0 : name.hashCode()); 7 return result; 8 } 9 @Override 10 public boolean equals(Object obj) { 11 if (this == obj) 12 return true; 13 if (obj == null) 14 return false; 15 if (getClass() != obj.getClass()) 16 return false; 17 Student other = (Student) obj; 18 if (age != other.age) 19 return false; 20 if (name == null) { 21 if (other.name != null) 22 return false; 23 } else if (!name.equals(other.name)) 24 return false; 25 return true; 26 }
再次执行,输出结果:
{[email protected]=小明, [email protected]=王五, [email protected]=张三}
3