Map:键必须是唯一
同步方法:Map m = Collections.synchronizedMap(new TreeMap(...));
Hashtable:基于散列表的实现 允许空键空值 线程安全
HashMap:基于散列表的实现 允许空键空值 线程不安全 (与Hashtable基本一致)
TreeMap: 基于红黑树数据结构的实现 不允许空键空值 线程不安全
WeakHashMap:改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收。
在除需要排序时使用TreeSet,TreeMap外,都应使用HashSet,HashMap,因为他们的效率更高。
HashTable:
import java.util.Hashtable; public class Main { public static void main(String[] args) { Hashtable ht = new Hashtable(); ht.put(new A(60000) , "11"); ht.put(new A(87563) , "22"); ht.put(new A(1232) , new B()); System.out.println(ht); //只要两个对象通过equals比较返回true, //Hashtable就认为它们是相等的value。 //由于Hashtable中有一个B对象, //它与任何对象通过equals比较都相等,所以下面输出true。 System.out.println(ht.containsValue("测试字符串")); //① //只要两个A对象的count相等,它们通过equals比较返回true,且hashCode相等 //Hashtable即认为它们是相同的key,所以下面输出true。 System.out.println(ht.containsKey(new A(87563))); //② //下面语句可以删除最后一个key-value对 ht.remove(new A(1232)); //③ //通过返回Hashtable的所有key组成的Set集合, //从而遍历Hashtable每个key-value对 for (Object key : ht.keySet()) { System.out.print(key + "---->"); System.out.print(ht.get(key) + " "); } } } class A { int count; public A(int count) { this.count = count; } //根据count的值来判断两个对象是否相等。 public boolean equals(Object obj) { if (obj == this) return true; if (obj!=null && obj.getClass()==A.class) { A a = (A)obj; return this.count == a.count; } return false; } //根据count来计算hashCode值。 public int hashCode() { return this.count; } } class B { //重写equals()方法,B对象与任何对象通过equals()方法比较都相等 public boolean equals(Object obj) { return true; } }
{com.company.A@ea60=11, com.company.A@1560b=22, com.company.A@4d0=com.company.B@5451c3a8} true true com.company.A@ea60---->11 com.company.A@1560b---->22
LinkedHashMap:
import java.util.LinkedHashMap; public class Main { public static void main(String[] args) { LinkedHashMap scores = new LinkedHashMap(); scores.put("语文" , 80); scores.put("英文" , 82); scores.put("数学" , 76); //遍历scores里的所有的key-value对 for (Object key : scores.keySet()) { System.out.println(key + "------>" + scores.get(key)); } } }
语文------>80 英文------>82 数学------>76
Properties:
import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Properties; public class Main { public static void main(String[] args) { try { Properties props = new Properties(); //向Properties中增加属性 props.setProperty("username", "yeeku"); props.setProperty("password", "123456"); //将Properties中的key-value对保存到a.ini文件中 props.store(new FileOutputStream("a.ini"), "comment line"); //① //新建一个Properties对象 Properties props2 = new Properties(); //向Properties中增加属性 props2.setProperty("gender", "male"); //将a.ini文件中的key-value对追加到props2中 props2.load(new FileInputStream("a.ini")); //② } catch(Exception e){ e.printStackTrace(); } } }
#comment line #Thu Nov 10 13:45:53 CST 2016 password=123456 username=yeeku
会在项目根目录生成一个a.ini文件
import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.util.Properties; public class Main { public static void main(String[] args) { Properties p = new Properties(); p.setProperty("id","dean"); p.setProperty("password","123456"); System.out.println(p); try{ PrintStream fW = new PrintStream(new File("d:\test1.properties")); p.list(fW ); } catch (IOException e) { e.printStackTrace(); } } }
import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Properties; public class Main { public static void main(String[] args) { try { Properties prop = new Properties();// 属性集合对象 FileInputStream fis = new FileInputStream("prop.properties");// 属性文件输入流 prop.load(fis);// 将属性文件流装载到Properties对象中 fis.close();// 关闭流 // 获取属性值,sitename已在文件中定义 System.out.println("获取属性值:sitename=" + prop.getProperty("sitename")); // 获取属性值,country未在文件中定义,将在此程序中返回一个默认值,但并不修改属性文件 System.out.println("获取属性值:country=" + prop.getProperty("country", "中国")); // 修改sitename的属性值 prop.setProperty("sitename", "Boxcode"); // 添加一个新的属性studio prop.setProperty("studio", "Boxcode Studio"); // 文件输出流 FileOutputStream fos = new FileOutputStream("prop.properties"); // 将Properties集合保存到流中 prop.store(fos, "Copyright (c) Boxcode Studio"); fos.close();// 关闭流 } catch(Exception e){ e.printStackTrace(); } } }
TreeMap:
import java.util.TreeMap; public class Main { public static void main(String[] args) { TreeMap tm = new TreeMap(); tm.put(new R(3) , "11"); tm.put(new R(-5) , "22"); tm.put(new R(9) , "33"); System.out.println(tm); //返回该TreeMap的第一个Entry对象 System.out.println(tm.firstEntry()); //返回该TreeMap的最后一个key值 System.out.println(tm.lastKey()); //返回该TreeMap的比new R(2)大的最小key值。 System.out.println(tm.higherKey(new R(2))); //返回该TreeMap的比new R(2)小的最大的key-value对。 System.out.println(tm.lowerEntry(new R(2))); //返回该TreeMap的子TreeMap System.out.println(tm.subMap(new R(-1) , new R(4))); } } class R implements Comparable { int count; public R(int count) { this.count = count; } public String toString() { return "R[count:" + count + "]"; } //根据count来判断两个对象是否相等。 public boolean equals(Object obj) { if (this == obj) return true; if (obj!=null && obj.getClass()==R.class) { R r = (R)obj; return r.count == this.count; } return false; } //根据count属性值来判断两个对象的大小。 public int compareTo(Object obj) { R r = (R)obj; return count > r.count ? 1 : count < r.count ? -1 : 0; } }
{R[count:-5]=22, R[count:3]=11, R[count:9]=33} R[count:-5]=22 R[count:9] R[count:3] R[count:-5]=22 {R[count:3]=11}
Set和Map的关系十分密切,java源码就是先实现了HashMap、TreeMap等集合,然后通过包装一个所有的value都为null的Map集合实现了Set集合类
WeakHashMap:
import java.util.WeakHashMap; public class Main { public static void main(String[] args) { WeakHashMap whm = new WeakHashMap(); //将WeakHashMap中添加三个key-value对, //三个key都是匿名字符串对象(没有其他引用) whm.put(new String("语文") , new String("良好")); whm.put(new String("数学") , new String("及格")); whm.put(new String("英文") , new String("中等")); //将WeakHashMap中添加一个key-value对, //该key是一个系统缓存的字符串对象。"java"是一个常量字符串强引用 whm.put("java" , new String("中等")); //输出whm对象,将看到4个key-value对。 System.out.println(whm); //通知系统立即进行垃圾回收 System.gc(); System.runFinalization(); //通常情况下,将只看到一个key-value对。 System.out.println(whm); } }
{英文=中等, java=中等, 数学=及格, 语文=良好}
{java=中等}
如果需要使用WeakHashMap的key来保留对象的弱引用,则不要让key所引用的对象具有任何强引用,否则将失去使用WeakHashMap的意义
IdentityHashMap:
import java.util.IdentityHashMap; public class Main { public static void main(String[] args) { IdentityHashMap ihm = new IdentityHashMap(); //下面两行代码将会向IdentityHashMap对象中添加两个key-value对 ihm.put(new String("语文") , 89); ihm.put(new String("语文") , 78); System.out.println(ihm); //下面两行代码只会向IdentityHashMap对象中添加一个key-value对 ihm.put("java" , 93); ihm.put("java" , 98); System.out.println(ihm); } }
{语文=89, 语文=78}
{语文=89, java=98, 语文=78}
EnumMap:
import java.util.EnumMap; public class Main { public static void main(String[] args) { //创建一个EnumMap对象,该EnumMap的所有key //必须是Season枚举类的枚举值 EnumMap enumMap = new EnumMap(Season.class); enumMap.put(Season.SUMMER , "夏日炎炎"); enumMap.put(Season.SPRING , "春暖花开"); System.out.println(enumMap); } } enum Season { SPRING,SUMMER,FALL,WINTER }
{SPRING=春暖花开, SUMMER=夏日炎炎}
与创建普通Map有所区别的是,创建EnumMap是必须指定一个枚举类,从而将该EnumMap和指定枚举类关联起来
Map集合类的编程应用场景:
1) HashMap和Hashtable的效率大致相同,因为它们的实现机制几乎完全一样。但HashMap通常比Hashtable要快一点,因为Hashtable需要额外的线程同步控制 2) TreeMap通常比HashMap、Hashtable要慢(尤其是在插入、删除key-value对时更慢),因为TreeMap底层采用红黑树来管理key-value对 3) 使用TreeMap的一个好处就是: TreeMap中的key-value对总是处于有序状态,无须专门进行排序操作