您的位置:首页 > 职场人生

黑马程序员-4-java-Collection集合类知识串讲(3)-Map及其子类

2015-05-26 17:38 381 查看
------- android培训java培训、期待与您交流!
----------

从图1.Java中集合类的关系图中不难看出,Map从根本上讲,并不是Collection的子类。确切的来说,Map类才应该是Collection类的实现基础。

Map类接口是与Collection不一样的一种集合,该集合存储的键值对,是成对的,而且对应的元素的关键字是唯一的。Map类集合是双列集合,与之相较,Collection类即为单列集合。Map类也包含了常用的增删改查方法,但是,与Collection不同的是,这里有两个可操作的参数。这点我们通过其类名Map <K , V>就可以看出。这也就是说,当程序中出现映射关系时,首先就要考虑Map集合。下面,我们来看一下它所具有的常用声明:

增:put ( K key , V value ) :添加一个元素进入Map类对象末尾;因为元素的关键字是唯一的,当使用put方法的时候,该方法会将所添加元素,按照他所对应的关键字,添加到对应关键字位置,并覆盖原有权值,这时候,put方法就会把原有的对应该关键字的权值返回回来。

putAll ( Maps < ? extends K , ?extends V > m) :将另一个Map类型对象添加至调用他的对象的末尾;

删:clear ( ) :清空调用该函数的Map类对象;

remove ( Object k ) :移除关键字为k的元素;

改:put即可实现;

查:get ( Object k ) :获取对应关键字为k值的元素;这里需要注意一点的是,我们可以通过个get方法来判断对应的Map类对象是否存在,当然,这种判断方法用在对应的Hashtable类当中是最合适的,因为该类不会出现赋值为空的情况。但是,这并不表示着这种判断存在的方法只能用在Hashtable类中,在大多数情况下,我们都是将这种方法放在HashMap类中使用的,因为,实际上赋值为空的情况是没有意义的一般很少出现

size ( ) :获取调用该函数的Map类对象的大小;

value ( ) :返回调用他的Map类对象关于其中元素权值的一个Collection类对象,这个函数的作用就是为了拿值;

set <k> keySet ( ) :返回调用该方法的Map类对象的关键字的Set类视图;

set <Map.Entry < k , v >>entrySet ( ) :返回调用该方法的Map类对象的元素映射关系的Set类视图,而这个关系的数据类型就是Map.Entry< k, v>;

判断:containValue ( Object v ) :判断调用该函数的类中是否有权值为v的元素;

containKey ( Object k ) :判断调用该函数的类中是否有关键字为k的元素;

isEmpty ( ) :继承自Object的通用方法。

这里面我们需要强调的是两个方法,一个是entrySet,另一个是keySet。

首先,我们来看keySet的使用思想。keySet方法是返回对应调用它的Map类对象的一个关于其所有关键字的一个集合。因为,Map类中并没有采用迭代器Iterator,所以,如果我们想的到所有关键字所对应的权值,我们只能通过get方法来实现了,那们首先我们需要做的就是得到所有的关键字,然后通过关键字来调用对应的权值。

接着,我们来看entrySet的使用思想。

该方法中使用了Map.Entry接口实现了多态,因为方法与Map.Entry接口紧密相关,这里我们就说一下Map.Entry接口声明的方法。该类声明的方法有:equals、getKey、getValue、setValue、hashCode,其中setValue为可选操作。看了该接口类声明的方法后,我们不难理解,其位于Map类中的地位,是可以类比Iterator接口类在Collection类中的作用的。都是为了实现一种跟便捷的提取对象数据的方式,而定义的类。而实质上,Entry其实是Map接口的一个public型静态内部接口。这样定义是因为,Entry类需要直接调用Map类中的数据,而从逻辑上来看,Entry只有在Map类存在后,才有可能存在。所以,他也被称为映射项。它相当于一个能够实现同时提取关键字和对应权值的封装集。

那么,在知道了这个后,entrySet方法实现大量数据的提取的思路,就变得明了起来了。那就是通过entrySet函数生成对应的Set类对象,在通过类对象调用迭代器实现,只不过这种方式,是一次同时提取了关键字相关权值而已。

由此,我们可以看出Map类取出数据,是不需要定义迭代器的,如果我们需要大量取出数据的话,我们首先考虑的是将Map类对象,从中抽象出对应的Set类对象,然后再通过Set类来生成并调用迭代器,实现对元素的大批量提取。这就是Map类大量提取数据的思想核心。下面是Map中常用方法演示:

class MyMap
{
public static void main (String[] args)
{
Map<String,String> map = newMap<String,String> ();

//添加元素,对应的前面是关键字,后面是权值
map.put("01","zhansan");
map.put("02","lisi");
map.put("03","wangwu");

sop(map);

//下面来看看各种方法的效果:
sop("put condition:");
sop("put:"+map.put("01","hongdoudou"));

sop("get condition:");           //这里体现了get方法判断元素是否存在
sop("get:"+map.get("02"));
sop("get_failed:"+map.get("06"));

sop("removecondition:");
sop("remove:"+map.remove("02"));

sop("contain condition:");
sop("containKey:"+map.containKey("01"));
sop("containKey_failed:"+map.containKey("06"));
sop("containValue:"+map.containValue("zhangsan"));
sop("containValue_failed:"+map.containValue("ph"));

sop("isemptycondition:");
sop("isempty:"+map.isEmpty());
sop("removecondition:");

sop("value condition:"); //value方法返回的是Collection类对象
Collection<String> c =map.value();
sop("value:"+c);

//下面,我们来看一下两大重要提取方法的使用:
//首先是keySet使用思想举例:
sop("keySetcondition:");
Set<String> set =map.keySet();
Iterator<String> ite =set.iterator();
for(String key; ite.hasNext(); key= ite.next())
{
sop("key:"+key+"  "+"value:"+map.get(key));
}

//然后我们来看一下entryKey的使用思想
sop("entrySetcondition:");
Set<Map.Entry<String,String>>set = map.entrySet();
Iterator<Map.Entry<String,String>>ite = set.iterator();
for(Map.Entry<String,String>en;ite.hasNext();en=ite.next())
{
String key = en.getKey();
String value =en.getValue();
sop("key:"+key+"  "+"value:"+value);
}

}
public static void sop(Object obj)
{
System.out.println (obj);
}
}


同时,如果是自定义类的话,则自定义类作为关键字的情况,必须覆写自定义类中的hashCode和equals方法,以保证关键字的唯一性,原理即自定义类判断重复的过程(前文中有总结)是由这两个函数决定的。先hashCode,再equals。

根据不同的需求和数据类型,我们实现Map接口时,有以下几种子类供我们实例化时使用:

Hashtable:此类用来实现哈希表,并将对应的关键字映射到与之相应的权值上(哈希算法)。但是,需要注意的是,给该类对象添加的元素的关键字和权值,不能为null对象,同时,该类也是同步的(即,加了类锁)。

HashMap:底层是哈希表数据结构,较之Hashtable类来说,它可以用null对象来给关键字和权值赋值,而且,他是不同步的(即,没有加锁)。因此,HashMap的效率高,但是没有Hashtable类安全(这也是相较而言的)。

TreeMap:此类所具有的数据结构是二叉树结构,因此,可以用于给对应的Map类双列集合的数据进行排序。这点特点可以参照对应Collection类字迹Set中的TreeSet类,做一个类比。同时,该类是不同步的(即没有加类锁)

既然存在二叉树的数据结构存储的Map类子类,那么自然有排序问题,我们用下面这个学生排序的列子来说明这个问题:

class Studentimplements Comparable
{
private String id;
private String name;
Student(String id,String name)
{
this.id=id;
this.name=name;
}
public int hashCode()
{
return(Integer.phrase(id)*5+24)/3;
}
public boolean equals(Object obj)
{
if(!(obj insatnceof Student))
throw newRuntimeException("error_wrongWithType");
new Student s = (Student)obj;
//比较学号和姓名,忽略大小写
boolean res1 =this.name.equalsIgnorCase(S.getName());
boolean res2 = this.id.equals(S.getID());
return res1 && res2;
}
public int compareTo(Object obj)
{
if(!(obj insatnceof Student))
throw newRuntimeException("error_wrongWithType");
new Student s = (Student)obj;
int n =this.id.compareTo(s.getID()); //记录id比较值
if(n==0)
{
return(this.name.compareTo(s.getName()));
}
}
public String getID()
{
return this.id;
}
public String getName()
{
return this.name;
}
}

class myComparatorimplements Comparator<Student>
{
compare(Student s1,Student S2)
{
S1.compareTo(S2);
}
}

class MyMapTest
{
public static void main(String[] args)
{
//Map类中TreeMap子类的两种排序方式,这个和TreeSet是一样的:
//第一种,通过元素自身顺序排序:
TreeMap<Student,int> tm1 =new TreeMap<Student,int>();
tm1.put(newStudent("01","zhao"),19);
tm1.put(new Student("02","qian"),21);
tm1.put(newStudent("03","sun"),18);
tm1.put(newStudent("04","li"),21);

getTree(tm1);

//第二种,通过比较器排序:
TreeMap<Student,int> tm2 =new TreeMap<Student,int>(new myComparator());
tm2.put(newStudent("01","zhao"),19);
tm2.put(newStudent("02","qian"),21);
tm2.put(newStudent("03","sun"),18);
tm2.put(newStudent("04","li"),21);

getTree(tm2);

}
public static void getTree(TreeMap t)
{
Set<Map.Entry<Student,int>>set = t.entrySet();
Iterator ite = set.iterator();
for(Map.Entry<Student,int>en;ite.hasNext();en=ite.next())
{
String key = en.getKey();
String value =en.getValue();
sop("key:"+key+"  "+"value:"+value);
}
}
public static void sop(Object obj)
{
System.out.println (obj);
}
}

值得一提的是Set接口最底层方法所调用的其实就是Map类接口的方法声明。只不过划分以及归类的时候,我们根据他的特性将其归到了Collection类接口所对应的单列集合中。比如,在Hashtable类中就描述了hashCode和equals方法在使用哈希类型时的注意事项,而正是应为HashSet类的底层是继承自Hashtable的,所以它也继承了对应的规则。这样举例虽然有些牵强,但是大概就是这样。

------- android培训java培训、期待与您交流!
----------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: