1 Collection集合的特点是每次进行单个对象的保存,每次对一对对象进行保存用Map集合。
Collection存储数据的目的是为了输出,Map存储对象的目的是为了查找。当然两者都能输出查找。
Map接口的定义:
public interface Map<K,V>
在Map接口里面有如下几个常用方法:
public V put(K,V)//向集合中添加数据
public Set<Map.Entry<K,V>>entry//将Map集合变为Set集合。
public V get(Object key)//根据key取得对应的value,如果没有,返回空
public Set<K>keySet()//取得所有的key信息,key不能重复(因为set接口不允许重复)
public Collection<V>values//取得所有value值,不关注内容是否重复,key不能重复
Map接口的常用的子类有HashMap,HashTable,TreeMap,ConcurrentHashMap
2 HashMap子类
(1)示例:Map的基本处理。
public class Test {
public static void main(String[] args) {
Map<Integer,String> map=new HashMap<>();
map.put(3,"java");
map.put(1, "hellow");
map.put(1, "world");//key重复了
map.put(2,"mldn");
System.out.println(map);//一次性全部输出
System.out.println(map.get(1));
System.out.println(map.get(55));//没有这个key值,所以返回空值。
}
}
结果:1=world, 2=mldn, 3=java}
world
null
可以看出,其结果是无序的,就是说输出结果和你输入的先后顺序无关。key重复了
(2)示例:取出一个Map中所有的key信息(不重要,没意义)
public class Test {
public static void main(String[] args) {
Map<Integer,String> map=new HashMap<>();
map.put(3,"java");
map.put(1, "hellow");
map.put(1, "world");//key重复了
map.put(2,"mldn");
Set<Integer> set=map.keySet();//取得所有key信息
Iterator<Integer> iter=set.iterator();//集合的输出想Iterator
while(iter.hasNext())
{
System.out.println(iter.next());
}
}
}
结果是:
1
2
3
面试题:解释HashMap的原理
在数据量小的时候,HashMap是按照链表的模式存储的。当数据量变大之后,为了进行快速的查找,会将这个链表变成红黑树(均衡二叉树),用hash码作为数据的定位来进行保存。
(3)Hashtable
Hashtable是最早实现这种二元偶对象数据结构,后期设计的时候也让其与Vector一样,多实现了Map接口而已。
示例:
public class Test {
public static void main(String[] args) {
Map<Integer,String> map=new Hashtable<>();
map.put(3,"java");
map.put(1, "hellow");
map.put(1, "world");//key重复了
map.put(2,"mldn");
System.out.println(map);
}
}
结果: {3=java, 2=mldn, 1=world}
(4)Hashtable与HashMap的区别
先看下面两个代码:
public class Test {
public static void main(String[] args) {
Map<Integer,String> map=new Hashtable<>();
map.put(3,"java");
map.put(1, "hellow");
map.put(1, "world");//key重复了
map.put(2,"mldn");
map.put(2, null);
map.put(null, null);
System.out.println(map);
}
}
结果:Exception in thread "main" java.lang.NullPointerException
at java.util.Hashtable.put(Hashtable.java:514)
at Test.main(Test.java:15)
public class Test {
public static void main(String[] args) {
Map<Integer,String> map=new HashMap<>();
map.put(3,"java");
map.put(1, "hellow");
map.put(1, "world");//key重复了
map.put(2,"mldn");
map.put(2, null);
map.put(null, null);
System.out.println(map);
}
}
结果: {null=null, 1=world, 2=null, 3=java}
总结:
区别 | HashMap | Hashtable |
性能 | 同步处理,性能较低 | 异步处理,性能高 |
安全性 | 线程安全 | 非线程安全 |
null操作 | 允许存放null | key和value不允许为空 |
(5)ConcurrentHashMap
ConcurrentHashMap的特点=HashMap的高性能+Hashtable的线程安全性。ConcurrentHashMap可以保证多个线程更新数据的同步,又可以保证很高效的查询速度。
示例:
public class Test {
public static void main(String[] args) {
Map<Integer,String> map=new ConcurrentHashMap<>();
map.put(3,"java");
map.put(1, "hellow");
map.put(1, "world");//key重复了
map.put(2,"mldn");
System.out.println(map);
}
}
结果:{2=mldn, 1=world, 3=java}
(6)利用Iterator输出Map集合
注意:在实际的开发之中,如果存储数据是为了输出,优先考虑Collection,使用Map的主要操作就是设置内容,而后通过get()进行查找的。
Map接口没有Iterator()方法,Collection中有。
在Map接口里有一个重要的方法,将Map集合转为Set集合:public Set<Map.Entry<K,V>>entrySet();
示例:利用Iterator输出Map集合
public class Test {
public static void main(String[] args) throws Exception{
Map<Integer,String> map=new HashMap<>();
map.put(1, "hellow");
map.put(2, "world");
//1.将Map集合变为Set集合
Set<Map.Entry<Integer, String>> set=map.entrySet();
//2实例化Iterator接口
Iterator<Map.Entry<Integer, String>> iter=set.iterator();
/**
* 取得当前元素:public E next();
* 判断是否有下一个元素:public boolean hasNext();
*/
//3迭代输出,取出每一个Map.Entry对象
while(iter.hasNext())
{
Map.Entry<Integer, String> me=iter.next();//4取出Map.Entry对象
System.out.println(me.getKey()+"="+me.getValue());
}
}
}
结果:1=hellow
2=world
(7)自定义Map的key类型
在使用Map集合的时候之前使用的都是系统类作为了KEY(Integer),那么实际上用户也可以采用自定义的类作为Key。
接下来我们可以分别使用String作为Key值,再用对象作为Key值。
class Person
{
private String name;
//构造方法
public Person(String name)
{
this.name=name;
}
public String toString()
{
return "name="+this.name;
}
}
public class Test {
public static void main(String[] args) throws Exception{
Map<String,Person> map=new HashMap<>();
map.put(new String("zs"), new Person("张三"));
System.out.println(map.get(new String("zs")));
}
}
结果: name=张三
再用对象作为Key值时:
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
class Person
{
private String name;
//构造方法
public Person(String name)
{
this.name=name;
}
public String toString()
{
return "name="+this.name;
}
}
public class Test {
public static void main(String[] args) throws Exception{
Map<Person,String> map=new HashMap<>();
map.put(new Person("张三"), new String("zs"));
System.out.println(map.get(new Person("张三")));
}
}
结果:null
通过上面2个程序可以看出,在用对象作为key值时,一定记得覆写Object类中的hashCode()方法与equals()方法。注意可以用eclipse中的source中的选项自动生成这两个方法。
class Person
{
private String name;
//构造方法
public Person(String name)
{
this.name=name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
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 (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
public String toString()
{
return "name="+this.name;
}
}
public class Test {
public static void main(String[] args) throws Exception{
Map<Person,String> map=new HashMap<>();
map.put(new Person("张三"), new String("zs"));
System.out.println(map.get(new Person("张三")));
}
}
总结:因为在实际的开发中,对于Map集合中的Key的类型不是使用String就是使用Integer这些系统类,他们已经帮用户覆写好了hashCode()方法与equals()方法,
所以在使用自定义的对象作为Key时要进行覆写这两个类。
(8)TreeMap子类
TreeMap表示可以排序的Map子类,它是按照Key的内容进行排序的。
示例:
public class Test {
public static void main(String[] args) throws Exception{
Map<Integer,String> map=new TreeMap<>();
map.put(2,"c");
map.put(0,"x");
map.put(1,"b");
System.out.println(map);
}
}
结果: {0=x, 1=b, 2=c}
总结:我们可以看出,这个时候的排序处理依然按照Comparable接口完成 的。
再看如下的例子:
class Person
{
private String name;
//构造方法
public Person(String name)
{
this.name=name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
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 (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
public String toString()
{
return "name="+this.name;
}
}
public class Test {
public static void main(String[] args) throws Exception{
Map<Person,String> map=new TreeMap<>();
map.put(new Person("张三"), new String("zs"));
System.out.println(map.get(new Person("张三")));
}
}
结果是:Exception in thread "main" java.lang.ClassCastException: Person cannot be cast to java.lang.Comparable
at java.util.TreeMap.compare(TreeMap.java:1188)
at java.util.TreeMap.put(TreeMap.java:531)
at Test.main(Test.java:57)
没有实现Comparable接口,所以改正后如下(实现有个Comparable接口,同时重写父类方法comparaTo):
class Person implements Comparable<Person>
{
private String name;
//构造方法
public Person(String name)
{
this.name=name;
}
@Override
public int compareTo(Person o) {
// TODO Auto-generated method stub
return this.name.compareTo(o.name);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
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 (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
public String toString()
{
return "name="+this.name;
}
}
public class Test {
public static void main(String[] args) throws Exception{
Map<Person,String> map=new TreeMap<>();
map.put(new Person("张三"), new String("zs"));
System.out.println(map.get(new Person("张三")));
}
}
结果:zs此时正确,如果将hashCode和equals删除,如下:
class Person implements Comparable<Person>
{
private String name;
//构造方法
public Person(String name)
{
this.name=name;
}
@Override
public int compareTo(Person o) {
// TODO Auto-generated method stub
return this.name.compareTo(o.name);
}
public String toString()
{
return "name="+this.name;
}
}
public class Test {
public static void main(String[] args) throws Exception{
Map<Person,String> map=new TreeMap<>();
map.put(new Person("张三"), new String("zs"));
System.out.println(map.get(new Person("张三")));
}
}
结果:zs
总结:有Comparable出现的地方判断数据就不用hasCode和equals方法了.用compareTo()即可。但是这种情况不常见,这类操作,key的类型使用最多的是String和Integer。
而这两个都是Compara接口的子类,所以不用写出来。
总结2:Collection保存数据的目的是为了输出,Map保存数据的目的是根据key查找value,找不到key返回null。
Map使用Iterator输出。