为什么80%的码农都做不了架构师?>>>
更多实现类的源码分析请点击链接地址。。。。。。。
一: java.util.Map<k,v>
public interface Map<K,V> { //....}
Map用于保存具有映射关系的数据,因此Map集合(键值对的集合)里保存着两组值,一组值用于保存Map里的key,另外一组用于保存Map里的value。
Map中的 key 和 value 都可以是任何引用类型的数据。
Map中的 Key 不允许重复,即同一个Map对象的任何两个 Key 通过 equals 方法比较中返回 false。
key 和 value 之间存在单向一对一关系,即通过指定的key总能找到唯一的,确定的value。
将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
接下来将介绍Map中部分实现类:
HashMap ,HashTable, TreeMap, LinkedHashMap , Properties
二: java.util.HashMap<k,v>
HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
{
...
/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/
transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
}
HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。源码如下:
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
int hash;
.....
}
更多内容源码分析请学习:
http://beyond99.blog.51cto.com/1469451/429789/
http://alex09.iteye.com/blog/539545
接下来简单了解下HashMaori中的基本方法:
首先定义一个Person:
public class Person implements Comparable<Person> {
private String name;
private int age;
@Override
public int compareTo(Person p) {
if(p instanceof Person ){
// return this.name.compareTo( p.name); 按升序排序
return p.name.compareTo( this.name );
}else{
throw new ClassCastException("非Person类型。");
}
}
/**
* 提供 构造方法,get set方法,hashCode 与 equals方法。
* */
}
然后在来看看HashMap的遍历:
public class Test1HashMap { public static void main(String[] args) { Map<String,Person> map = new HashMap<String,Person>(); Person p1 = new Person("Berg", 22); Person p2 = new Person("AA",21); Person p3 = new Person("BB",20); Person p4 = new Person("DD",23); Person p5 = new Person("EE",25); Person p6 = new Person("CC",19); //Map.put(String key, Person value) map.put("1", p1); map.put("2", p2); map.put("3", p3); map.put("4", p4); map.put("5", p5); map.put("6", p6); System.out.println( map.size() ); System.out.println( map.containsKey( "6" )); System.out.println( map.containsValue( p2 )); System.out.println( "\n通过for循环Map.Entry遍历Map: "); // 接下来对map的遍历: //1. for循环遍历map for( Map.Entry<String, Person> entry : map.entrySet() ){ System.out.println( entry.getKey() +" : "+ entry.getValue() ); } System.out.println( "\n通过KeySet + Iterator 迭代遍历Map:"); // 2. 迭代 Set<String> set = map.keySet(); Iterator iterator = set.iterator(); while( iterator.hasNext() ){ String key = iterator.next().toString(); Person p = map.get(key); System.out.println( key + " : " + p ); } // 3. System.out.println( "\n通过entrySert方式遍历Map "); Set<Entry<String, Person>> setentry = map.entrySet(); Iterator<Entry<String, Person>> iteratorSet = setentry.iterator(); while( iteratorSet.hasNext() ){ Entry<String, Person> entry = iteratorSet.next(); System.out.println( entry.getKey() + " : " + entry.getValue() ); } } }
更多HashMap源码内容分析请学习:
http://blog.csdn.net/chenssy/article/details/18323767
三: java.util.HashTable<k,v>
此类实现一个哈希表,该哈希表将键映射到相应的值。任何非 null
对象都可以用作键或值。
为了成功地在哈希表中存储和获取对象,用作键的对象必须实现 hashCode
方法和 equals
方法。
public class Hashtable<K,V> extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable {
/**
* The hash table data.
*/
private transient Entry<K,V>[] table;
}
了解下HashMap与HashTable的区别:
第一,继承不同。
public class Hashtable<K,V> extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
第二
Hashtable 中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。
第三
Hashtable中,key和value都不允许出现null值。
在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。
第四,两个遍历方式的内部实现上不同。
Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。
第五
哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。
第六
Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。
public class Test2HashTable {
public static void main(String[] args) {
Hashtable<String,String> ht = new Hashtable<String,String>();
ht.put("1", "AAA");
ht.put("2", "BBB");
ht.put("3", "DDD");
ht.put("4", "EEE");
ht.put("5", "CCC");
Enumeration<String> enumeration = ht.keys();
while ( enumeration.hasMoreElements() ){
System.out.print( enumeration.nextElement().toString() +" " );
}
//遍历
for(Entry<String, String> entry: ht.entrySet() ){
System.out.println( entry.getKey() + " : " + entry.getValue() );
}
}
}
更多HashTable源码内容分析请学习:
http://blog.csdn.net/chenssy/article/details/22896871
四: java.util.LinkedHashMap
Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现与 HashMap 的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。注意,如果在映射中重新插入 键,则插入顺序不受影响。
注意:LinkedHashMap继承自HashMap,如下:
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>{}
注意:
HashMap使用哈希表来存储数据,并用拉链法来处理冲突。
LinkedHashMap继承自HashMap,同时自身有一个链表,使用链表存储数据,不存在冲突。
LinkedList和LinkedHashMap一样使用一个双向循环链表,但存储的是简单的数据,并不是“键值对”。
所以HashMap和LinkedHashMap是Map,而LinkedList是一个List,这是他们本质的区别。
LinkedList和LinkedHashMap都可以维护内容的顺序,但HashMap不维护顺序。
public class Test3LinkedHashMap {
public static void main(String[] args) {
LinkedHashMap<String, String> map = new LinkedHashMap<>();
map.put("1", "AAA");
map.put("2", "BBB");
map.put("3", "DDD");
map.put("4", "EEE");
map.put("5", "CCC");
// 遍历
for(Entry<String, String> entry: map.entrySet() ){
System.out.println( entry.getKey() + " : " + entry.getValue() );
}
}
}
更多LinkedHashMap源码内容分析请学习:
http://blog.csdn.net/jzhf2012/article/details/8540688
五: java.util.TreeMap<k,v>
基于红黑树(Red-Black tree)的 NavigableMap实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator进行排序,具体取决于使用的构造方法。
public class TreeMap<K,V> extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
/**
* The comparator used to maintain order in this tree map, or
* null if it uses the natural ordering of its keys.
*
* @serial
*/
private final Comparator<? super K> comparator;
private transient Entry<K,V> root = null;
}
注意:
TreeMap 存储Key-Value对时,需要根据Key对 key-value对进行排序。
TreeMap 可以保证所有的Key-Value的Key的排序。
TreeMap 的Key的排序:
-自然排序:TreeMap的所有的Key必须实现Comparable接口,而且所有的key应该是同一个类的对象,否则会抛出ClassCastException。
-定制排序:创建TreeMap时,传入一个Comparator对象,该对象负责对TreeMap中的所有的key进行排序,此时不需要Map的key实现Comparable接口。
首先先看看Person 与 Person2的不同:
前者实现了Comparable 而后者没有,如下:
Person:
public class Person implements Comparable<Person> {
private String name;
private int age;
@Override
public int compareTo(Person p) {
if(p instanceof Person ){
// return this.name.compareTo( p.name); 按升序排序
return p.name.compareTo( this.name );
}else{
throw new ClassCastException("非Person类型。");
}
}
/**
* 提供 构造方法,get set方法,hashCode 与 equals方法。
* */
}
Person2:
public class Person2{
private String name;
private int age;
}
然后比较两种不同方式的排序:
public class Test4TreeMap { public static void main(String[] args) { // Person实现Comparable , TreeMap<Person,String> map = new TreeMap<Person,String>(); Person p1 = new Person("Berg", 22); Person p2 = new Person("AA",21); Person p3 = new Person("BB",20); Person p4 = new Person("DD",23); Person p5 = new Person("EE",25); // 可以尝试将下面的 K V 对换以下, //但是当用 Person对象当做 key的时候,Person必须实现Comparable map.put(p1, "AAA"); map.put(p2, "BBB"); map.put(p3, "DDD"); map.put(p4, "EEE"); map.put(p5, "CCC"); // 遍历 , 默认按照键的自然顺序排序 且升序排序 for(Entry<Person, String> entry: map.entrySet() ){ System.out.println( entry.getKey() + " : " + entry.getValue() ); } System.out.println( "\n\n定制排序**********************"); //********************************************** // 不需要Person2对象实现Comparable接口。 //根据创建映射时提供的 Comparator进行排序 Comparator<Object> comparator = new Comparator<Object>() { @Override public int compare(Object o1, Object o2) { if( o1 instanceof Person2 && o2 instanceof Person2){ Person2 p1 = (Person2) o1; Person2 p2 = (Person2) o2; return p2.getAge() - p1.getAge(); }else{ throw new ClassCastException("非Person2类型。"); } } }; TreeMap<Person2,String> map1 = new TreeMap<Person2,String>(comparator); Person2 p21 = new Person2("AA", 19); Person2 p22 = new Person2("BB", 20); Person2 p23 = new Person2("CC", 21); Person2 p24 = new Person2("EE", 23); Person2 p25 = new Person2("DD", 24); Person2 p26 = new Person2("AA", 19); map1.put(p21, "AAA"); map1.put(p22, "BBB"); map1.put(p23, "DDD"); map1.put(p24, "EEE"); map1.put(p25, "CCC"); map1.put(p26, "AAA"); // 遍历 , 默认按照键的自然顺序排序 且升序排序 for(Entry<Person2, String> entry: map1.entrySet() ){ System.out.println( entry.getKey() + " : " + entry.getValue() ); } } }
更多TreeMap源码内容分析请学习:
http://blog.csdn.net/chenssy/article/details/26668941
六: java.util.Peroperties
Properties 类是 HashTable的子类,该对象用于处理属性文件。
由于属性文件里的key value都是字符串类型, 所以properties里的key 和 value 都是字符串类型的。
public class Properties extends Hashtable<Object,Object> { ...}
先看看一个db.properties中文件内容:
username=xujun
password=berg
blogaddress=http://my.oschina.net/gently/blog
然后读取这个属性文件:
public class Test5Properties {
public static void main(String[] args) throws IOException {
//以流的方式读取属性文件。
// 文件是从SRC根目录下开始扫描。
InputStream iis= Test5Properties.class.getClassLoader().getResourceAsStream( "db.properties" );
//创建对象
Properties p = new Properties();
//通过load将流中的数据读取到P中,形成键值。
p.load( iis ); // inputstream
//p.load( iis ); reader
for( Map.Entry entry : p.entrySet() ){
System.out.println( entry.getKey() +"\t"+ entry.getValue() );
}
iis.close();
}
}
输出:
blogaddress http://my.oschina.net/gently/blog;
password berg;
username xujun;