Java集合系列(五)

前言

之前所讲解的Collection,Set,List接口都属于单值的操作,即每次只能操作一个对象,而Map接口与它们不同的是,每次操作的是一对对象,即二元偶对象,Map接口中的每一个元素都使用“key->value”的形式存储在集合中。Map的定义如下:

public interface Map<K,V>

这里写图片描述

Map.Entry接口简介

Map.Entry是使用static关键字声明的内部接口,此接口可以由外部通过”外部类.内部类”的形式直接调用。在本接口中提供了如表所示的方法:
这里写图片描述

从之前的内容可以知道,在Map接口的操作中,所有的内容都是通过key-value的形式保存数据的,那么对于集合来说,实际上是将key-value的数据保存在了Map.Entry接口的实例之后,再在Map集合中插入的是一个Map.Entry的实例化对象,如图所示:
这里写图片描述

Map接口的常用子类

与之前的Collection接口类似,如果想要使用Map接口也必须依靠其子类实例化。Map接口中常用的子类介绍如下。

  • HashMap: 无序存放的,是新的操作类,key不允许重复。
  • HashTable: 无序存放的, 是旧的操作类,key不允许重复。
  • TreeMap:可以排序的Map集合,按集合中的key排序,key不允许重复。
  • WeakHashMap:弱引用的Map集合,当集合中的某些内容不再使用时清除掉无用的数据,使用gc进行回收。
  • IdentityHashMap:key可以重复的Map集合。

新的子类:HashMap

HashMap本身是Map的子类,直接使用此类为Map接口实例化即可。
HashMap类的定义如下:

public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>,Cloneable,Serializable

HashMap是AbstractMap类的子类,AbstractMap类的定义如下:

public abstract class AbstractMap<K,V> extends Object implements Map<K,V>

通过使用HashMap来为读者讲解Map接口放入主要操作方法。

操作一:向集合中增加和取出内容

import java.util.HashMap;
import java.util.Map;
public class HashMapDemo01{
public static void main(String[] args){
Map<String,String>map=null;
map=new HashMap<String,String>();
map.put("A","a");
map.put("B","b");
map.put("C","c");
map.put("D","d");
String val=map.get("A");
System.out.println("取出的内容是:"+val);
  }
}

在程序中通过声明Map接口对象时指定好了key和value的泛型类型为String,之后通过put()方法向Map集合中增加内容,最后通过get()方法取出一个key对应的value内容。

操作二:判断指定的key或value是否存在

import java.util.Map;
import java,util.HashMap;
public class HashMapDemo02{
public static void main(Sting[] args){
Map<String,String> map=null;
map=new HashMap<String,String>();
map.put("A","a");
map.put("B","b");
map.put("C","c");
map.put("D","d");
if(map.containsKey("A")){
System.out.println("搜素的key存在!");
}else{
System.out.println("搜索的key不存在!");
}
if(map.containValue("a")){
System.out.println("搜索的value存在!");
}else{
System.out.println("搜索的value不存在");

实例操作三:输出全部的key

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashMapDemo03{
public static void main(String[] args){
Map<Strring,String> map=null;
map=new HashMap<String,String>();
map.put("A","a");
map.put("B","b");
map.put("C","c");
map.put("D","d");
Set<String> keys=map.keySet();  //得到全部的key
Iterator<String> iter=keys.iterator(); //实例化Iterator
System.out.print("全部的key:");
while(iter.hasNext()){
String str=iter.next();
System.out.print(str+",");
     }
   }
 }     

实例操作四:输出全部的value

import java.util.HashMap;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
public class HashMapDemo04{
public static void main(String[] args ){
Map<String,Strng> map=null;
map=new HashMap<String,String>();
map.put("A","a");
map.put("B","b");
map.put("C","c");
Colection<String> values=map.values();  //得到全部的value
Iterator<String> iter=values.Iterator(); //实例化Iterator
System.out.print("全部的value:");
while(iter.hasNext()){
String str =iter.next();
System.out.print(str+",");
    }
  }
} 

旧的子类:Hashtable操作

Hashtable也是Map接口的一个子类,与Vector类的推出时间一样,都属于旧的操作类,其使用上也和之前没有什么太大的区别

Hashtable的操作

import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashtableDemo01{
public static void main(String[] args){
Map<String,String> map=null;
map=new Hashtable<String,String>();
map.put("A","a");
map.put("B","b");
map.put("C","c");
Set<String> keys=map.keySet(); //得到全部的key
Iterator<String> iter1=keys.iterator();//实例化Iterator
System.out.print("全部的key:"); //输出信息
while(iter1.hasNext()){  //迭代输出全部的key
String str=iter.next();  //取出内容 
System.out.print(str+ ",");  //输出内容
}
Collection<String> values=map.values(); //得到全部的value
Iterator<String> iter2=values.iterator();//实例化Iterator
System.out.print("\n全部的value:");
while(iter2.hasNext()){
String str =iter2.next();
System.out.print(str+",");
    }
  }
}

HashMap与Hashtable的区别

  • HashMap:采用异步处理方式,性能更高,属于非线程安全的操作类,允许null键和null值。

  • Hashtable:采用同步处理方式,性能较低,属于线程安全的操作类,不允许null键,否则将出现Null pointer Exception异常。

以上对两个类进行了比较,但是从实际的开发应用来看,HashMap类使用较多。

排序的子类:TreeMap

import java .util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class TreeMapDemo01{
public static void main(String[] args){
Map<String,String> map=null; 
map=new TreeMap<String,String>(); //实例化map对象
map.put("A","a");
map.put("B","b");
map.put("C","c");
Set<String> keys=map.keySet();  //得到全部的key
Iterator<String> iter=keys.iterator();
while(iter.hasNext()){  //迭代输出
String str=iter.next();  //取出key
System.out.println(str+"__>"+map.get(str)); //取出key对应的内容
     }
   }
 }    

注意

使用自定义类做为key时必须实现Comparable接口

弱引用类:WeakHashMap

之前所讲解的Map接口的子类中的数据都是使用强引用保存的,即里面的内容不管是否使用都始终在集合中保留,如果希望集合自动清理暂时不用的数据就使用WeakHashMap类。这样,当进行垃圾收集时会释放掉集合中的垃圾信息,WeakHashMap的定义如下:

public class WeakHashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>

对象的引用强度说明

Java把对象的引用分为4种级别,从而使程序更加灵活地控制对象的生命周期。这4种级别由高到低依次为:强引用,软引用,弱引用和虚引用。下面介绍这4种引用的区别。

  • 强引用:当内存不足时,JVM宁可出现OOM Error错误而使程序停止,也不会回收此对象来释放空间。

  • 软引用: 当内存不足时,会回收这些对象的内存,用来实现内存敏感的高速缓存。

  • 弱引用:无论内存是否紧张,被垃圾回收器发现立即回收。

  • 虚引用:和没有任何引用一样

Map接口的使用注意事项

1.注意事项一:不能直接使用迭代输出Map中的全部内容

对于Map接口来说,其本身是不能直接使用迭代(如Iterator,foreach)进行输出的,因为Map接口中的每一个位置存放的是一对值(key->value),而Iterator中每次只能找到一个值。所以,如果非要使用迭代输出,则必须按照以下步骤完成(以Iterator输出方法为例)。
(1) 将Map接口的实例通过entrySet()方法变为Set接口对象。
(2) 通过Set接口实例为Iterator实例化
(3)通过Iterator迭代输出,每个内容都是Map.Entry的对象。
(4)通过Map.Entry进行key-value的分离

在前面提到过,Map中的每对数据都是通过Map.Entry保存的,所以如果最终要进行输出应该使用Map.Entry接口完成。下面通过Iterator和foreach来为读者演示Map的输出。

提示

Map一般很少直接输出,只是作为查询使用

Map输出方式一:Iterator输出Map

import java.util.HashMap;
import java,util.Iterator;
import java.util.Map;
import java.util.Set;
public class IteratorDemo04{
public static void main(String[] args){
map<String,String> map=null;
map=new HashMap<String,String>();
map.put("A","a");
map.put("B","b");
map.put("C","c");
Set<Map.Entry<String,String>> allSet=null; //声明一个Set集合,指定泛型
allSet=map.entrySet(); //将Map接口实例变为Set接口实例
Iterator<Map.Entry<String,String>> iter=null;
iter=allSet.iterator();
while(iter.hasNext()){   
Map.Entry<String,String> me=iter.next(); //找到Map.Entry实例
System.out.println(me.getKey()+"-->" +me.getValue)//输出key和value
      }
    }
 }     

以上操作是Map输出最标准的操作流程,读者一定要牢牢掌握,这一点在以后的开发中非常重要。

Map输出方式二:foreach输出Map

既然可以使用Iterator接口进行输出,那么也就是说使用foreach进行输出,输出时还是要将Map集合变为Set集合,Set集合中的每一个元素都是Map.Entry对象。

import java.util.Iterator;
import java.util.Map;
public class ForeachDemo02{
public static void main(String[] args){
Map<String,String> map=null; //声明map对象,指定泛型
map=new HashMap<Sring,String>();  //实例化map对象
map.put("A","a");
map.put("B""b");
map.put("C","c");
for(Map.Entry<String,String> me:map.entrySet()){
System.out.println(me.getKey()+"-->" +me.getValue());
      }
   }
}      

覆写equals()和hashCode()方法

import java.util.HashMap;
import java.util.Map;
class Person{
private Sring name;
ptivate int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
public boolean equals(Object obj){
if(this==obj){
return true;
}
if(!(obj instanceof Person)){
return false;
}
Person p=(Person)obj;  //进行向下转型
if(this.name.equals(p.name)&&this.age==p.age){
return true;
}else{
return false;
}
}
public int hashCode(){
return this.name.hashCode()*this.age;
}
public String toString(){
return "姓名:"+this.name+":年龄:"+this.age;
}
}
public class HashMapDemo{
public static void main(String[] args){
Map<Person,Srting>map=null;
map=new HashMap<Person,String>();
Person per=new Person("张三", 30);
map.put(per,"zhangsan");
System.out.println(map.get(per));
  }
}  

程序运行结果:

zhangsan

从程序的运行结果中可以发现,如果要使用一个自定义的对象表示Map中的key,则对象所在类中一定要覆写equals()和hashCode方法;否则无法通过匿名对象找到相应的value。

总结

  • 集合的目的是用来创建动态的对象数组操作。

  • Collection接口是集合中的最大单值操作的付接口,但是一般开发中不会直接使用此接口,而常使用List或Set接口。

  • List接口扩展了Coleection接口,里面的内容是允许重复的。

  • List接口的常用子类是ArrayList和Vector,在开发中ArrayList性能较高,属于异步处理,而Vector性能较低,属于同步处理。

  • Set接口与Collection接口的定义一致,里面的内容不允许重复的,依靠Object类中的equals()和hashCode()方法来区分是否是同一个对象

  • Set接口的常用子类是HashSet和TreeSet,前者是散列存放,没有顺序;后者是顺序存放,使用Comparable进行排序操作。

  • 集合的输出要使用Iterator接口完成,Iterator属于迭代输出接口。

  • 在JDK 1.5之后集合也可以使用foreach的方式输出。

  • Enumeration属于最早的迭代输出接口,现在基本很少使用,在集合中Vector类可以使用Enumeration接口进行内容的输出

  • List集合的操作可以使用ListIterator接口进行双向的输出操作。

  • Map中的常用子类是HashMap,TreeMap,HashTable。HashMap属于异步处理,性能较高;TreeMap属于排序类,按照Comparable指定的顺序进行key的排序;Hashtable属于同步处理,性能较低。

  • 类集中提供了Collection工具类完成类集的相关操作。

  • Stack类可以完成先进后出的操作。

  • Propertics类属于属性操作类,使用属性操作类可以直接操作属性文件,属性文件可以按普通文件或者XML的文件格式进行保存。

  • 使用集合可以方便的拜师一对多及多对多的关系

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bryce李小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值