集合(四): Map

news/2024/7/7 10:06:54

为什么80%的码农都做不了架构师?>>>   hot3.png

 

更多实现类的源码分析请点击链接地址。。。。。。。

一:    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;

 

 

 

转载于:https://my.oschina.net/gently/blog/691404


http://www.niftyadmin.cn/n/2422844.html

相关文章

mysql 留言及回复_mysql - 用PHP写留言板,有回复功能,要写入数据库。

为情所困2017-05-24 11:36:301楼第一&#xff0c;最好不要和反饋信息表設計在同一張表裡。第二&#xff0c;你的反饋表最好加多一個字段status,表示該條信息是否已回复。反饋表設計id[int(11)]主鍵suggest_id[int(11)]反饋表idaid[int(11)]反饋人員idcontent[text]反饋信息isus…

mysql靶机_[Vulnhub]靶机渗透-Raven:2

0x01 Scan Host更加详细地扫描:0x02 Web Service还是有个wp&#xff0c;老规矩用wpscan看一下&#xff0c;同时扫描目录。flag1dirb扫描出错&#xff0c;所以这里用gobuster:挨个看了下发现了flag1:刚好wpscan的结果也出来了&#xff0c;wordpress的版本是4.8.7&#xff0c;主题…

第一节课作业 150206119

c语言首先老师提供一个C语言的飞机游戏让大家感受一下&#xff0c;首先安装c-free&#xff0c;然后是将代码进行运行&#xff0c;游戏以A.S.D.W键位来控制游戏中飞机的上下左右&#xff0c;击中敌机可获得积分&#xff0c;被敌机撞中死亡一次&#xff0c;每次游戏有3次生还机会…

Android 主题动态切换框架:Prism

Prism&#xff08;棱镜&#xff09; 是一个全新的 Android 动态主题切换框架&#xff0c;虽然是头一次发布&#xff0c;但它所具备的基础功能已经足够强大了&#xff01;本文介绍了 Prism 的各种用法&#xff0c;希望对你会有所帮助&#xff0c;你也可以对它进行扩展&#xff0…

openmp 互斥锁 mysql_并发读写OpenMp中的共享变量

我基本上有三个关于OpenMp的问题。并发读写OpenMp中的共享变量Q1。 OpenMp是否提供互斥共享变量&#xff1f;考虑下面的三个嵌套循环的简单矩阵乘法代码&#xff0c;使用C中的OpenMp并行化。这里A&#xff0c;B和C是动态空间分配双**类型的变量。线程数被适当分配一个值。#prag…

java idgenerator_Java IdGenerator.newId方法代码示例

import com.hazelcast.core.IdGenerator; //导入方法依赖的package包/类/*** {inheritDoc}*/Overridepublic void start(ClusterManager manager) throws AndesException{this.manager manager;/*** register topic listeners for cluster events. This has to be done* after…

Gartner:2016年十大信息安全技术(含解读)

在刚刚结束的2016年Gartner安全与风险管理峰会上&#xff0c;发布了2016年十大信息安全技术&#xff08;http://www.gartner.com/newsroom/id/3347717&#xff09;。这里提及的10大技术基本上都在以往的报告中详细阐述过。这10大技术分别是&#xff1a;1&#xff09;云访问安全…

English - every和each的用法和区别

两者都有“每个”的意思,但用法不同&#xff1a; &#xff08;1&#xff09;each具有名词和形容词的功能,every只有形容词的功能. &#xff08;2&#xff09;each指两个或两个以上的人或事物中的“每个”&#xff1b;every是指三个以上的人或事物的“全体”,和all的意思相近.如…