您的位置:首页 > 其它

Map集合,HashMap,HashTable,ConCurrentHashMap,利用Iterator输出Map集合,自定义Map的key类型,TreeMap子类详解

2018-03-30 08:48 501 查看
(一)Map接口
   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不允许为空。
 所以尽量多用HashMap。如果在自己的线程中,用哪个都行,如果不是,看情况。去桌面找相应的图片    
     
     
     
  (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输出。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Map
相关文章推荐